From 8c71ec8f11dd3e8f5163df48d1175c975aa19973 Mon Sep 17 00:00:00 2001 From: jljusten Date: Wed, 15 Aug 2012 00:03:59 +0000 Subject: [PATCH] OvmfPkg: Add custom SecureBootConfigDxe that doesn't reset We don't force a platform reset for OVMF when PK is changed in custom mode setup. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Lee Rosenbaum Reviewed-by: Erik Bjorge Reviewed-by: Jordan Justen git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13635 6f19259b-4bc3-4df7-8a09-765794883524 --- OvmfPkg/OvmfPkgIa32.dsc | 2 +- OvmfPkg/OvmfPkgIa32.fdf | 6 +- OvmfPkg/OvmfPkgIa32X64.dsc | 2 +- OvmfPkg/OvmfPkgIa32X64.fdf | 6 +- OvmfPkg/OvmfPkgX64.dsc | 2 +- OvmfPkg/OvmfPkgX64.fdf | 6 +- .../SecureBootConfigDxe/SecureBootConfig.vfr | 495 +++ .../SecureBootConfigDevicePath.c | 1537 +++++++++ .../SecureBootConfigDriver.c | 133 + .../SecureBootConfigDxe.inf | 105 + .../SecureBootConfigFileExplorer.c | 1227 ++++++++ .../SecureBootConfigImpl.c | 2804 +++++++++++++++++ .../SecureBootConfigImpl.h | 614 ++++ .../SecureBootConfigMisc.c | 334 ++ .../SecureBootConfigNvData.h | 118 + .../SecureBootConfigStrings.uni | Bin 0 -> 9518 bytes 16 files changed, 7379 insertions(+), 12 deletions(-) create mode 100644 OvmfPkg/SecureBootConfigDxe/SecureBootConfig.vfr create mode 100644 OvmfPkg/SecureBootConfigDxe/SecureBootConfigDevicePath.c create mode 100644 OvmfPkg/SecureBootConfigDxe/SecureBootConfigDriver.c create mode 100644 OvmfPkg/SecureBootConfigDxe/SecureBootConfigDxe.inf create mode 100644 OvmfPkg/SecureBootConfigDxe/SecureBootConfigFileExplorer.c create mode 100644 OvmfPkg/SecureBootConfigDxe/SecureBootConfigImpl.c create mode 100644 OvmfPkg/SecureBootConfigDxe/SecureBootConfigImpl.h create mode 100644 OvmfPkg/SecureBootConfigDxe/SecureBootConfigMisc.c create mode 100644 OvmfPkg/SecureBootConfigDxe/SecureBootConfigNvData.h create mode 100644 OvmfPkg/SecureBootConfigDxe/SecureBootConfigStrings.uni diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc index 453a5788cb..232e010e12 100644 --- a/OvmfPkg/OvmfPkgIa32.dsc +++ b/OvmfPkg/OvmfPkgIa32.dsc @@ -527,5 +527,5 @@ BaseCryptLib|CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf } - SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf + OvmfPkg/SecureBootConfigDxe/SecureBootConfigDxe.inf !endif diff --git a/OvmfPkg/OvmfPkgIa32.fdf b/OvmfPkg/OvmfPkgIa32.fdf index f31d002192..f819e6b59b 100644 --- a/OvmfPkg/OvmfPkgIa32.fdf +++ b/OvmfPkg/OvmfPkgIa32.fdf @@ -170,7 +170,7 @@ INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf !if $(SECURE_BOOT_ENABLE) == TRUE INF SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf - INF SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf + INF OvmfPkg/SecureBootConfigDxe/SecureBootConfigDxe.inf !else INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf !endif @@ -356,7 +356,7 @@ FILE FV_IMAGE = 9E21FD93-9C72-4c15-8C4B-E77F1DB2D792 { UI STRING="$(MODULE_NAME)" Optional VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) } - + [Rule.Common.UEFI_APPLICATION] FILE APPLICATION = $(NAMED_GUID) { PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi @@ -370,7 +370,7 @@ FILE FV_IMAGE = 9E21FD93-9C72-4c15-8C4B-E77F1DB2D792 { UI STRING="$(MODULE_NAME)" Optional VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) } - + [Rule.Common.USER_DEFINED.ACPITABLE] FILE FREEFORM = $(NAMED_GUID) { RAW ACPI |.acpi diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc index 73e8c987b5..c095df935d 100644 --- a/OvmfPkg/OvmfPkgIa32X64.dsc +++ b/OvmfPkg/OvmfPkgIa32X64.dsc @@ -529,5 +529,5 @@ BaseCryptLib|CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf } - SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf + OvmfPkg/SecureBootConfigDxe/SecureBootConfigDxe.inf !endif diff --git a/OvmfPkg/OvmfPkgIa32X64.fdf b/OvmfPkg/OvmfPkgIa32X64.fdf index 71c9b981f0..399f01321c 100644 --- a/OvmfPkg/OvmfPkgIa32X64.fdf +++ b/OvmfPkg/OvmfPkgIa32X64.fdf @@ -170,7 +170,7 @@ INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf !if $(SECURE_BOOT_ENABLE) == TRUE INF SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf - INF SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf + INF OvmfPkg/SecureBootConfigDxe/SecureBootConfigDxe.inf !else INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf !endif @@ -356,7 +356,7 @@ FILE FV_IMAGE = 9E21FD93-9C72-4c15-8C4B-E77F1DB2D792 { UI STRING="$(MODULE_NAME)" Optional VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) } - + [Rule.Common.UEFI_APPLICATION] FILE APPLICATION = $(NAMED_GUID) { PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi @@ -370,7 +370,7 @@ FILE FV_IMAGE = 9E21FD93-9C72-4c15-8C4B-E77F1DB2D792 { UI STRING="$(MODULE_NAME)" Optional VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) } - + [Rule.Common.USER_DEFINED.ACPITABLE] FILE FREEFORM = $(NAMED_GUID) { RAW ACPI |.acpi diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc index 1c2aec0cdc..d742c1cae1 100644 --- a/OvmfPkg/OvmfPkgX64.dsc +++ b/OvmfPkg/OvmfPkgX64.dsc @@ -527,5 +527,5 @@ BaseCryptLib|CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf } - SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf + OvmfPkg/SecureBootConfigDxe/SecureBootConfigDxe.inf !endif diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf index e234f4fdae..6a5bcb6fad 100644 --- a/OvmfPkg/OvmfPkgX64.fdf +++ b/OvmfPkg/OvmfPkgX64.fdf @@ -170,7 +170,7 @@ INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf !if $(SECURE_BOOT_ENABLE) == TRUE INF SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf - INF SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf + INF OvmfPkg/SecureBootConfigDxe/SecureBootConfigDxe.inf !else INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf !endif @@ -356,7 +356,7 @@ FILE FV_IMAGE = 9E21FD93-9C72-4c15-8C4B-E77F1DB2D792 { UI STRING="$(MODULE_NAME)" Optional VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) } - + [Rule.Common.UEFI_APPLICATION] FILE APPLICATION = $(NAMED_GUID) { PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi @@ -370,7 +370,7 @@ FILE FV_IMAGE = 9E21FD93-9C72-4c15-8C4B-E77F1DB2D792 { UI STRING="$(MODULE_NAME)" Optional VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) } - + [Rule.Common.USER_DEFINED.ACPITABLE] FILE FREEFORM = $(NAMED_GUID) { RAW ACPI |.acpi diff --git a/OvmfPkg/SecureBootConfigDxe/SecureBootConfig.vfr b/OvmfPkg/SecureBootConfigDxe/SecureBootConfig.vfr new file mode 100644 index 0000000000..22c03c1288 --- /dev/null +++ b/OvmfPkg/SecureBootConfigDxe/SecureBootConfig.vfr @@ -0,0 +1,495 @@ +/** @file + VFR file used by the SecureBoot configuration component. + +Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "SecureBootConfigNvData.h" + +formset + guid = SECUREBOOT_CONFIG_FORM_SET_GUID, + title = STRING_TOKEN(STR_SECUREBOOT_TITLE), + help = STRING_TOKEN(STR_SECUREBOOT_HELP), + classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID, + + varstore SECUREBOOT_CONFIGURATION, + varid = SECUREBOOT_CONFIGURATION_VARSTORE_ID, + name = SECUREBOOT_CONFIGURATION, + guid = SECUREBOOT_CONFIG_FORM_SET_GUID; + + // + // ##1 Form "Secure Boot Configuration" + // + form formid = SECUREBOOT_CONFIGURATION_FORM_ID, + title = STRING_TOKEN(STR_SECUREBOOT_TITLE); + + subtitle text = STRING_TOKEN(STR_NULL); + + // + // Define of Check Box: Attempt Secure Boot + // + suppressif TRUE; + checkbox varid = SECUREBOOT_CONFIGURATION.HideSecureBoot, + prompt = STRING_TOKEN(STR_NULL), + help = STRING_TOKEN(STR_NULL), + endcheckbox; + endif; + + // + // Display of Check Box: Attempt Secure Boot + // + grayoutif ideqval SECUREBOOT_CONFIGURATION.HideSecureBoot == 1; + checkbox varid = SECUREBOOT_CONFIGURATION.SecureBootState, + questionid = KEY_SECURE_BOOT_ENABLE, + prompt = STRING_TOKEN(STR_SECURE_BOOT_PROMPT), + help = STRING_TOKEN(STR_SECURE_BOOT_HELP), + flags = INTERACTIVE, + endcheckbox; + endif; + + // + // Display of Oneof: 'Secure Boot Mode' + // + oneof varid = SECUREBOOT_CONFIGURATION.SecureBootMode, + questionid = KEY_SECURE_BOOT_MODE, + prompt = STRING_TOKEN(STR_SECURE_BOOT_MODE_PROMPT), + help = STRING_TOKEN(STR_SECURE_BOOT_MODE_HELP), + flags = INTERACTIVE, + option text = STRING_TOKEN(STR_STANDARD_MODE), value = SECURE_BOOT_MODE_STANDARD, flags = DEFAULT; + option text = STRING_TOKEN(STR_CUSTOM_MODE), value = SECURE_BOOT_MODE_CUSTOM, flags = 0; + endoneof; + + // + // + // Display of 'Current Secure Boot Mode' + // + suppressif ideqval SECUREBOOT_CONFIGURATION.SecureBootMode == SECURE_BOOT_MODE_STANDARD; + grayoutif NOT ideqval SECUREBOOT_CONFIGURATION.PhysicalPresent == 1; + goto FORMID_SECURE_BOOT_OPTION_FORM, + prompt = STRING_TOKEN(STR_SECURE_BOOT_OPTION), + help = STRING_TOKEN(STR_SECURE_BOOT_OPTION_HELP), + flags = INTERACTIVE, + key = KEY_SECURE_BOOT_OPTION; + endif; + endif; + endform; + + // + // ##2 Form: 'Custom Secure Boot Options' + // + form formid = FORMID_SECURE_BOOT_OPTION_FORM, + title = STRING_TOKEN(STR_SECURE_BOOT_OPTION_TITLE); + + subtitle text = STRING_TOKEN(STR_NULL); + + goto FORMID_SECURE_BOOT_PK_OPTION_FORM, + prompt = STRING_TOKEN(STR_SECURE_BOOT_PK_OPTION), + help = STRING_TOKEN(STR_SECURE_BOOT_PK_OPTION_HELP), + flags = INTERACTIVE, + key = KEY_SECURE_BOOT_PK_OPTION; + + subtitle text = STRING_TOKEN(STR_NULL); + + goto FORMID_SECURE_BOOT_KEK_OPTION_FORM, + prompt = STRING_TOKEN(STR_SECURE_BOOT_KEK_OPTION), + help = STRING_TOKEN(STR_SECURE_BOOT_KEK_OPTION_HELP), + flags = INTERACTIVE, + key = KEY_SECURE_BOOT_KEK_OPTION; + + subtitle text = STRING_TOKEN(STR_NULL); + + goto FORMID_SECURE_BOOT_DB_OPTION_FORM, + prompt = STRING_TOKEN(STR_SECURE_BOOT_DB_OPTION), + help = STRING_TOKEN(STR_SECURE_BOOT_DB_OPTION_HELP), + flags = INTERACTIVE, + key = KEY_SECURE_BOOT_DB_OPTION; + + subtitle text = STRING_TOKEN(STR_NULL); + + goto FORMID_SECURE_BOOT_DBX_OPTION_FORM, + prompt = STRING_TOKEN(STR_SECURE_BOOT_DBX_OPTION), + help = STRING_TOKEN(STR_SECURE_BOOT_DBX_OPTION_HELP), + flags = INTERACTIVE, + key = KEY_SECURE_BOOT_DBX_OPTION; + + endform; + + // + // ##3 Form: 'PK Options' + // + form formid = FORMID_SECURE_BOOT_PK_OPTION_FORM, + title = STRING_TOKEN(STR_SECURE_BOOT_PK_OPTION); + + subtitle text = STRING_TOKEN(STR_NULL); + + // + // Define of Check Box: 'Delete PK' + // + suppressif TRUE; + checkbox varid = SECUREBOOT_CONFIGURATION.DeletePk, + prompt = STRING_TOKEN(STR_NULL), + help = STRING_TOKEN(STR_NULL), + endcheckbox; + endif; + + grayoutif ideqval SECUREBOOT_CONFIGURATION.HasPk == 1; + goto FORMID_ENROLL_PK_FORM, + prompt = STRING_TOKEN(STR_ENROLL_PK), + help = STRING_TOKEN(STR_ENROLL_PK_HELP), + flags = INTERACTIVE, + key = KEY_ENROLL_PK; + endif; + + subtitle text = STRING_TOKEN(STR_NULL); + + // + // Display of Check Box: 'Delete Pk' + // + grayoutif ideqval SECUREBOOT_CONFIGURATION.HideSecureBoot == 1; + checkbox varid = SECUREBOOT_CONFIGURATION.DeletePk, + questionid = KEY_SECURE_BOOT_DELETE_PK, + prompt = STRING_TOKEN(STR_DELETE_PK), + help = STRING_TOKEN(STR_DELETE_PK_HELP), + flags = INTERACTIVE, + endcheckbox; + endif; + endform; + + // + // ##4 Form: 'Enroll PK' + // + form formid = FORMID_ENROLL_PK_FORM, + title = STRING_TOKEN(STR_ENROLL_PK); + + subtitle text = STRING_TOKEN(STR_NULL); + + goto FORM_FILE_EXPLORER_ID_PK, + prompt = STRING_TOKEN(STR_SECURE_BOOT_ENROLL_PK_FILE), + help = STRING_TOKEN(STR_SECURE_BOOT_ENROLL_PK_FILE), + flags = INTERACTIVE, + key = SECUREBOOT_ADD_PK_FILE_FORM_ID; + endform; + + // + // ##5 Form: 'KEK Options' + // + form formid = FORMID_SECURE_BOOT_KEK_OPTION_FORM, + title = STRING_TOKEN(STR_SECURE_BOOT_KEK_OPTION); + + // + // Display of 'Enroll KEK' + // + goto FORMID_ENROLL_KEK_FORM, + prompt = STRING_TOKEN(STR_ENROLL_KEK), + help = STRING_TOKEN(STR_ENROLL_KEK_HELP), + flags = INTERACTIVE; + + subtitle text = STRING_TOKEN(STR_NULL); + + // + // Display of 'Delete KEK' + // + goto FORMID_DELETE_KEK_FORM, + prompt = STRING_TOKEN(STR_DELETE_KEK), + help = STRING_TOKEN(STR_DELETE_KEK_HELP), + flags = INTERACTIVE, + key = KEY_DELETE_KEK; + + subtitle text = STRING_TOKEN(STR_NULL); + endform; + + // + // ##6 Form: 'Enroll KEK' + // + form formid = FORMID_ENROLL_KEK_FORM, + title = STRING_TOKEN(STR_ENROLL_KEK_TITLE); + + subtitle text = STRING_TOKEN(STR_NULL); + + goto FORM_FILE_EXPLORER_ID_KEK, + prompt = STRING_TOKEN(STR_FORM_ENROLL_KEK_FROM_FILE_TITLE), + help = STRING_TOKEN(STR_FORM_ENROLL_KEK_FROM_FILE_TITLE_HELP), + flags = INTERACTIVE, + key = FORMID_ENROLL_KEK_FORM; + + subtitle text = STRING_TOKEN(STR_NULL); + label FORMID_ENROLL_KEK_FORM; + label LABEL_END; + subtitle text = STRING_TOKEN(STR_NULL); + + string varid = SECUREBOOT_CONFIGURATION.SignatureGuid, + prompt = STRING_TOKEN(STR_SECURE_BOOT_SIGNATURE_GUID), + help = STRING_TOKEN(STR_SECURE_BOOT_SIGNATURE_GUID_HELP), + flags = INTERACTIVE, + key = KEY_SECURE_BOOT_KEK_GUID, + minsize = SECURE_BOOT_GUID_SIZE, + maxsize = SECURE_BOOT_GUID_SIZE, + endstring; + + subtitle text = STRING_TOKEN(STR_NULL); + subtitle text = STRING_TOKEN(STR_NULL); + + goto FORMID_SECURE_BOOT_OPTION_FORM, + prompt = STRING_TOKEN(STR_SAVE_AND_EXIT), + help = STRING_TOKEN(STR_SAVE_AND_EXIT), + flags = INTERACTIVE, + key = KEY_VALUE_SAVE_AND_EXIT_KEK; + + goto FORMID_SECURE_BOOT_OPTION_FORM, + prompt = STRING_TOKEN(STR_NO_SAVE_AND_EXIT), + help = STRING_TOKEN(STR_NO_SAVE_AND_EXIT), + flags = INTERACTIVE, + key = KEY_VALUE_NO_SAVE_AND_EXIT_KEK; + + endform; + + // + // ##7 Form: 'Delete KEK' + // + form formid = FORMID_DELETE_KEK_FORM, + title = STRING_TOKEN(STR_DELETE_KEK_TITLE); + + label LABEL_KEK_DELETE; + label LABEL_END; + + subtitle text = STRING_TOKEN(STR_NULL); + + endform; + + // + // ##8 Form: 'DB Options' + // + form formid = FORMID_SECURE_BOOT_DB_OPTION_FORM, + title = STRING_TOKEN(STR_SECURE_BOOT_DB_OPTION); + + subtitle text = STRING_TOKEN(STR_NULL); + + goto SECUREBOOT_ENROLL_SIGNATURE_TO_DB, + prompt = STRING_TOKEN (STR_SECURE_BOOT_ENROLL_SIGNATURE), + help = STRING_TOKEN (STR_SECURE_BOOT_ENROLL_SIGNATURE), + flags = 0; + + subtitle text = STRING_TOKEN(STR_NULL); + + goto SECUREBOOT_DELETE_SIGNATURE_FROM_DB, + prompt = STRING_TOKEN (STR_SECURE_BOOT_DELETE_SIGNATURE), + help = STRING_TOKEN (STR_SECURE_BOOT_DELETE_SIGNATURE), + flags = INTERACTIVE, + key = SECUREBOOT_DELETE_SIGNATURE_FROM_DB; + + endform; + + // + // ##9 Form: 'DBX Options' + // + form formid = FORMID_SECURE_BOOT_DBX_OPTION_FORM, + title = STRING_TOKEN(STR_SECURE_BOOT_DBX_OPTION); + + subtitle text = STRING_TOKEN(STR_NULL); + + goto SECUREBOOT_ENROLL_SIGNATURE_TO_DBX, + prompt = STRING_TOKEN (STR_SECURE_BOOT_ENROLL_SIGNATURE), + help = STRING_TOKEN (STR_SECURE_BOOT_ENROLL_SIGNATURE), + flags = 0; + + subtitle text = STRING_TOKEN(STR_NULL); + + goto SECUREBOOT_DELETE_SIGNATURE_FROM_DBX, + prompt = STRING_TOKEN (STR_SECURE_BOOT_DELETE_SIGNATURE), + help = STRING_TOKEN (STR_SECURE_BOOT_DELETE_SIGNATURE), + flags = INTERACTIVE, + key = SECUREBOOT_DELETE_SIGNATURE_FROM_DBX; + + endform; + + // + // Form: 'Delete Signature' for DB Options. + // + form formid = SECUREBOOT_DELETE_SIGNATURE_FROM_DB, + title = STRING_TOKEN(STR_SECURE_BOOT_DELETE_SIGNATURE); + + label LABEL_DB_DELETE; + label LABEL_END; + subtitle text = STRING_TOKEN(STR_NULL); + + endform; + + // + // Form: 'Delete Signature' for DBX Options. + // + form formid = SECUREBOOT_DELETE_SIGNATURE_FROM_DBX, + title = STRING_TOKEN(STR_SECURE_BOOT_DELETE_SIGNATURE); + + label LABEL_DBX_DELETE; + label LABEL_END; + subtitle text = STRING_TOKEN(STR_NULL); + + endform; + + // + // Form: 'Enroll Signature' for DB options. + // + form formid = SECUREBOOT_ENROLL_SIGNATURE_TO_DB, + title = STRING_TOKEN(STR_SECURE_BOOT_ENROLL_SIGNATURE); + + subtitle text = STRING_TOKEN(STR_NULL); + + goto FORM_FILE_EXPLORER_ID_DB, + prompt = STRING_TOKEN(STR_SECURE_BOOT_ADD_SIGNATURE_FILE), + help = STRING_TOKEN(STR_SECURE_BOOT_ADD_SIGNATURE_FILE), + flags = INTERACTIVE, + key = SECUREBOOT_ENROLL_SIGNATURE_TO_DB; + + subtitle text = STRING_TOKEN(STR_NULL); + label SECUREBOOT_ENROLL_SIGNATURE_TO_DB; + label LABEL_END; + subtitle text = STRING_TOKEN(STR_NULL); + + string varid = SECUREBOOT_CONFIGURATION.SignatureGuid, + prompt = STRING_TOKEN(STR_SECURE_BOOT_SIGNATURE_GUID), + help = STRING_TOKEN(STR_SECURE_BOOT_SIGNATURE_GUID_HELP), + flags = INTERACTIVE, + key = KEY_SECURE_BOOT_SIGNATURE_GUID_DB, + minsize = SECURE_BOOT_GUID_SIZE, + maxsize = SECURE_BOOT_GUID_SIZE, + endstring; + + subtitle text = STRING_TOKEN(STR_NULL); + subtitle text = STRING_TOKEN(STR_NULL); + + goto FORMID_SECURE_BOOT_OPTION_FORM, + prompt = STRING_TOKEN(STR_SAVE_AND_EXIT), + help = STRING_TOKEN(STR_SAVE_AND_EXIT), + flags = INTERACTIVE, + key = KEY_VALUE_SAVE_AND_EXIT_DB; + + goto FORMID_SECURE_BOOT_OPTION_FORM, + prompt = STRING_TOKEN(STR_NO_SAVE_AND_EXIT), + help = STRING_TOKEN(STR_NO_SAVE_AND_EXIT), + flags = INTERACTIVE, + key = KEY_VALUE_NO_SAVE_AND_EXIT_DB; + + endform; + + // + // Form: 'Enroll Signature' for DBX options. + // + form formid = SECUREBOOT_ENROLL_SIGNATURE_TO_DBX, + title = STRING_TOKEN(STR_SECURE_BOOT_ENROLL_SIGNATURE); + + subtitle text = STRING_TOKEN(STR_NULL); + + goto FORM_FILE_EXPLORER_ID_DBX, + prompt = STRING_TOKEN(STR_SECURE_BOOT_ADD_SIGNATURE_FILE), + help = STRING_TOKEN(STR_SECURE_BOOT_ADD_SIGNATURE_FILE), + flags = INTERACTIVE, + key = SECUREBOOT_ENROLL_SIGNATURE_TO_DBX; + + subtitle text = STRING_TOKEN(STR_NULL); + label SECUREBOOT_ENROLL_SIGNATURE_TO_DBX; + label LABEL_END; + subtitle text = STRING_TOKEN(STR_NULL); + + string varid = SECUREBOOT_CONFIGURATION.SignatureGuid, + prompt = STRING_TOKEN(STR_SECURE_BOOT_SIGNATURE_GUID), + help = STRING_TOKEN(STR_SECURE_BOOT_SIGNATURE_GUID_HELP), + flags = INTERACTIVE, + key = KEY_SECURE_BOOT_SIGNATURE_GUID_DBX, + minsize = SECURE_BOOT_GUID_SIZE, + maxsize = SECURE_BOOT_GUID_SIZE, + endstring; + + subtitle text = STRING_TOKEN(STR_NULL); + subtitle text = STRING_TOKEN(STR_NULL); + + goto FORMID_SECURE_BOOT_OPTION_FORM, + prompt = STRING_TOKEN(STR_SAVE_AND_EXIT), + help = STRING_TOKEN(STR_SAVE_AND_EXIT), + flags = INTERACTIVE, + key = KEY_VALUE_SAVE_AND_EXIT_DBX; + + goto FORMID_SECURE_BOOT_OPTION_FORM, + prompt = STRING_TOKEN(STR_NO_SAVE_AND_EXIT), + help = STRING_TOKEN(STR_NO_SAVE_AND_EXIT), + flags = INTERACTIVE, + key = KEY_VALUE_NO_SAVE_AND_EXIT_DBX; + + endform; + + // + // File Explorer for PK + // + form formid = FORM_FILE_EXPLORER_ID_PK, + title = STRING_TOKEN(STR_FILE_EXPLORER_TITLE); + + label FORM_FILE_EXPLORER_ID; + label LABEL_END; + endform; + + // + // File Explorer for KEK + // + form formid = FORM_FILE_EXPLORER_ID_KEK, + title = STRING_TOKEN(STR_FILE_EXPLORER_TITLE); + + label FORM_FILE_EXPLORER_ID; + label LABEL_END; + endform; + + // + // File Explorer for DB + // + form formid = FORM_FILE_EXPLORER_ID_DB, + title = STRING_TOKEN(STR_FILE_EXPLORER_TITLE); + + label FORM_FILE_EXPLORER_ID; + label LABEL_END; + endform; + + // + // File Explorer for DBX + // + form formid = FORM_FILE_EXPLORER_ID_DBX, + title = STRING_TOKEN(STR_FILE_EXPLORER_TITLE); + + label FORM_FILE_EXPLORER_ID; + label LABEL_END; + endform; + + + // + // Enroll Pk from File Commit Form + // + form formid = SECUREBOOT_ADD_PK_FILE_FORM_ID, + title = STRING_TOKEN(STR_SAVE_PK_FILE); + + label SECUREBOOT_ADD_PK_FILE_FORM_ID; + label LABEL_END; + + subtitle text = STRING_TOKEN(STR_NULL); + + text + help = STRING_TOKEN(STR_SAVE_AND_EXIT), + text = STRING_TOKEN(STR_SAVE_AND_EXIT), + text = STRING_TOKEN(STR_NULL), + flags = INTERACTIVE, + key = KEY_VALUE_SAVE_AND_EXIT_PK; + + text + help = STRING_TOKEN(STR_NO_SAVE_AND_EXIT), + text = STRING_TOKEN(STR_NO_SAVE_AND_EXIT), + text = STRING_TOKEN(STR_NULL), + flags = INTERACTIVE, + key = KEY_VALUE_NO_SAVE_AND_EXIT_PK; + + endform; + +endformset; diff --git a/OvmfPkg/SecureBootConfigDxe/SecureBootConfigDevicePath.c b/OvmfPkg/SecureBootConfigDxe/SecureBootConfigDevicePath.c new file mode 100644 index 0000000000..ae44626594 --- /dev/null +++ b/OvmfPkg/SecureBootConfigDxe/SecureBootConfigDevicePath.c @@ -0,0 +1,1537 @@ +/** @file + Internal function defines the default device path string for SecureBoot configuration module. + +Copyright (c) 2012, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "SecureBootConfigImpl.h" + +/** + Concatenates a formatted unicode string to allocated pool. + The caller must free the resulting buffer. + + @param[in, out] Str Tracks the allocated pool, size in use, and amount of pool allocated. + @param[in] Fmt The format string + @param[in] ... The data will be printed. + + @return Allocated buffer with the formatted string printed in it. + The caller must free the allocated buffer. + The buffer allocation is not packed. + +**/ +CHAR16 * +EFIAPI +CatPrint ( + IN OUT POOL_PRINT *Str, + IN CHAR16 *Fmt, + ... + ) +{ + UINT16 *AppendStr; + VA_LIST Args; + UINTN StringSize; + + AppendStr = AllocateZeroPool (0x1000); + if (AppendStr == NULL) { + return Str->Str; + } + + VA_START (Args, Fmt); + UnicodeVSPrint (AppendStr, 0x1000, Fmt, Args); + VA_END (Args); + if (NULL == Str->Str) { + StringSize = StrSize (AppendStr); + Str->Str = AllocateZeroPool (StringSize); + ASSERT (Str->Str != NULL); + } else { + StringSize = StrSize (AppendStr); + StringSize += (StrSize (Str->Str) - sizeof (UINT16)); + + Str->Str = ReallocatePool ( + StrSize (Str->Str), + StringSize, + Str->Str + ); + ASSERT (Str->Str != NULL); + } + + Str->Maxlen = MAX_CHAR * sizeof (UINT16); + if (StringSize < Str->Maxlen) { + StrCat (Str->Str, AppendStr); + Str->Len = StringSize - sizeof (UINT16); + } + + FreePool (AppendStr); + return Str->Str; +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathPci ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + PCI_DEVICE_PATH *Pci; + + Pci = DevPath; + CatPrint (Str, L"Pci(%x|%x)", (UINTN) Pci->Device, (UINTN) Pci->Function); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathPccard ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + PCCARD_DEVICE_PATH *Pccard; + + Pccard = DevPath; + CatPrint (Str, L"Pcmcia(Function%x)", (UINTN) Pccard->FunctionNumber); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathMemMap ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + MEMMAP_DEVICE_PATH *MemMap; + + MemMap = DevPath; + CatPrint ( + Str, + L"MemMap(%d:%lx-%lx)", + (UINTN) MemMap->MemoryType, + MemMap->StartingAddress, + MemMap->EndingAddress + ); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathController ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + CONTROLLER_DEVICE_PATH *Controller; + + Controller = DevPath; + CatPrint (Str, L"Ctrl(%d)", (UINTN) Controller->ControllerNumber); +} + + +/** + Convert Vendor device path to device name. + + @param[in, out] Str The buffer store device name + @param[in] DevPath Pointer to vendor device path + +**/ +VOID +DevPathVendor ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + VENDOR_DEVICE_PATH *Vendor; + CHAR16 *Type; + UINTN DataLength; + UINTN Index; + UINT32 FlowControlMap; + + UINT16 Info; + + Vendor = DevPath; + + switch (DevicePathType (&Vendor->Header)) { + case HARDWARE_DEVICE_PATH: + Type = L"Hw"; + break; + + case MESSAGING_DEVICE_PATH: + Type = L"Msg"; + if (CompareGuid (&Vendor->Guid, &gEfiPcAnsiGuid)) { + CatPrint (Str, L"VenPcAnsi()"); + return ; + } else if (CompareGuid (&Vendor->Guid, &gEfiVT100Guid)) { + CatPrint (Str, L"VenVt100()"); + return ; + } else if (CompareGuid (&Vendor->Guid, &gEfiVT100PlusGuid)) { + CatPrint (Str, L"VenVt100Plus()"); + return ; + } else if (CompareGuid (&Vendor->Guid, &gEfiVTUTF8Guid)) { + CatPrint (Str, L"VenUft8()"); + return ; + } else if (CompareGuid (&Vendor->Guid, &gEfiUartDevicePathGuid )) { + FlowControlMap = (((UART_FLOW_CONTROL_DEVICE_PATH *) Vendor)->FlowControlMap); + switch (FlowControlMap & 0x00000003) { + case 0: + CatPrint (Str, L"UartFlowCtrl(%s)", L"None"); + break; + + case 1: + CatPrint (Str, L"UartFlowCtrl(%s)", L"Hardware"); + break; + + case 2: + CatPrint (Str, L"UartFlowCtrl(%s)", L"XonXoff"); + break; + + default: + break; + } + + return ; + + } else if (CompareGuid (&Vendor->Guid, &gEfiSasDevicePathGuid)) { + CatPrint ( + Str, + L"SAS(%lx,%lx,%x,", + ((SAS_DEVICE_PATH *) Vendor)->SasAddress, + ((SAS_DEVICE_PATH *) Vendor)->Lun, + (UINTN) ((SAS_DEVICE_PATH *) Vendor)->RelativeTargetPort + ); + Info = (((SAS_DEVICE_PATH *) Vendor)->DeviceTopology); + if ((Info & 0x0f) == 0) { + CatPrint (Str, L"NoTopology,0,0,0,"); + } else if (((Info & 0x0f) == 1) || ((Info & 0x0f) == 2)) { + CatPrint ( + Str, + L"%s,%s,%s,", + ((Info & (0x1 << 4)) != 0) ? L"SATA" : L"SAS", + ((Info & (0x1 << 5)) != 0) ? L"External" : L"Internal", + ((Info & (0x1 << 6)) != 0) ? L"Expanded" : L"Direct" + ); + if ((Info & 0x0f) == 1) { + CatPrint (Str, L"0,"); + } else { + CatPrint (Str, L"%x,", (UINTN) ((Info >> 8) & 0xff)); + } + } else { + CatPrint (Str, L"0,0,0,0,"); + } + + CatPrint (Str, L"%x)", (UINTN) ((SAS_DEVICE_PATH *) Vendor)->Reserved); + return ; + + } else if (CompareGuid (&Vendor->Guid, &gEfiDebugPortProtocolGuid)) { + CatPrint (Str, L"DebugPort()"); + return ; + } + break; + + case MEDIA_DEVICE_PATH: + Type = L"Media"; + break; + + default: + Type = L"?"; + break; + } + + CatPrint (Str, L"Ven%s(%g", Type, &Vendor->Guid); + DataLength = DevicePathNodeLength (&Vendor->Header) - sizeof (VENDOR_DEVICE_PATH); + if (DataLength > 0) { + CatPrint (Str, L","); + for (Index = 0; Index < DataLength; Index++) { + CatPrint (Str, L"%02x", (UINTN) ((VENDOR_DEVICE_PATH_WITH_DATA *) Vendor)->VendorDefinedData[Index]); + } + } + CatPrint (Str, L")"); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathAcpi ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + ACPI_HID_DEVICE_PATH *Acpi; + + Acpi = DevPath; + if ((Acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { + CatPrint (Str, L"Acpi(PNP%04x,%x)", (UINTN) EISA_ID_TO_NUM (Acpi->HID), (UINTN) Acpi->UID); + } else { + CatPrint (Str, L"Acpi(%08x,%x)", (UINTN) Acpi->HID, (UINTN) Acpi->UID); + } +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathExtendedAcpi ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + ACPI_EXTENDED_HID_DEVICE_PATH *ExtendedAcpi; + + // + // Index for HID, UID and CID strings, 0 for non-exist + // + UINT16 HIDSTRIdx; + UINT16 UIDSTRIdx; + UINT16 CIDSTRIdx; + UINT16 Index; + UINT16 Length; + UINT16 Anchor; + CHAR8 *AsChar8Array; + + HIDSTRIdx = 0; + UIDSTRIdx = 0; + CIDSTRIdx = 0; + ExtendedAcpi = DevPath; + Length = (UINT16) DevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) ExtendedAcpi); + + AsChar8Array = (CHAR8 *) ExtendedAcpi; + + // + // find HIDSTR + // + Anchor = 16; + for (Index = Anchor; Index < Length && AsChar8Array[Index] != '\0'; Index++) { + ; + } + if (Index > Anchor) { + HIDSTRIdx = Anchor; + } + // + // find UIDSTR + // + Anchor = (UINT16) (Index + 1); + for (Index = Anchor; Index < Length && AsChar8Array[Index] != '\0'; Index++) { + ; + } + if (Index > Anchor) { + UIDSTRIdx = Anchor; + } + // + // find CIDSTR + // + Anchor = (UINT16) (Index + 1); + for (Index = Anchor; Index < Length && AsChar8Array[Index] != '\0'; Index++) { + ; + } + if (Index > Anchor) { + CIDSTRIdx = Anchor; + } + + if (HIDSTRIdx == 0 && CIDSTRIdx == 0 && ExtendedAcpi->UID == 0) { + CatPrint (Str, L"AcpiExp("); + if ((ExtendedAcpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { + CatPrint (Str, L"PNP%04x,", (UINTN) EISA_ID_TO_NUM (ExtendedAcpi->HID)); + } else { + CatPrint (Str, L"%08x,", (UINTN) ExtendedAcpi->HID); + } + if ((ExtendedAcpi->CID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { + CatPrint (Str, L"PNP%04x,", (UINTN) EISA_ID_TO_NUM (ExtendedAcpi->CID)); + } else { + CatPrint (Str, L"%08x,", (UINTN) ExtendedAcpi->CID); + } + if (UIDSTRIdx != 0) { + CatPrint (Str, L"%a)", AsChar8Array + UIDSTRIdx); + } else { + CatPrint (Str, L"\"\")"); + } + } else { + CatPrint (Str, L"AcpiEx("); + if ((ExtendedAcpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { + CatPrint (Str, L"PNP%04x,", (UINTN) EISA_ID_TO_NUM (ExtendedAcpi->HID)); + } else { + CatPrint (Str, L"%08x,", (UINTN) ExtendedAcpi->HID); + } + if ((ExtendedAcpi->CID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { + CatPrint (Str, L"PNP%04x,", (UINTN) EISA_ID_TO_NUM (ExtendedAcpi->CID)); + } else { + CatPrint (Str, L"%08x,", (UINTN) ExtendedAcpi->CID); + } + CatPrint (Str, L"%x,", (UINTN) ExtendedAcpi->UID); + + if (HIDSTRIdx != 0) { + CatPrint (Str, L"%a,", AsChar8Array + HIDSTRIdx); + } else { + CatPrint (Str, L"\"\","); + } + if (CIDSTRIdx != 0) { + CatPrint (Str, L"%a,", AsChar8Array + CIDSTRIdx); + } else { + CatPrint (Str, L"\"\","); + } + if (UIDSTRIdx != 0) { + CatPrint (Str, L"%a)", AsChar8Array + UIDSTRIdx); + } else { + CatPrint (Str, L"\"\")"); + } + } + +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathAdrAcpi ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + ACPI_ADR_DEVICE_PATH *AcpiAdr; + UINT16 Index; + UINT16 Length; + UINT16 AdditionalAdrCount; + + AcpiAdr = DevPath; + Length = (UINT16) DevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) AcpiAdr); + AdditionalAdrCount = (UINT16) ((Length - 8) / 4); + + CatPrint (Str, L"AcpiAdr(%x", (UINTN) AcpiAdr->ADR); + for (Index = 0; Index < AdditionalAdrCount; Index++) { + CatPrint (Str, L",%x", (UINTN) *(UINT32 *) ((UINT8 *) AcpiAdr + 8 + Index * 4)); + } + CatPrint (Str, L")"); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathAtapi ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + ATAPI_DEVICE_PATH *Atapi; + + Atapi = DevPath; + CatPrint ( + Str, + L"Ata(%s,%s)", + (Atapi->PrimarySecondary != 0)? L"Secondary" : L"Primary", + (Atapi->SlaveMaster != 0)? L"Slave" : L"Master" + ); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathScsi ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + SCSI_DEVICE_PATH *Scsi; + + Scsi = DevPath; + CatPrint (Str, L"Scsi(Pun%x,Lun%x)", (UINTN) Scsi->Pun, (UINTN) Scsi->Lun); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathFibre ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + FIBRECHANNEL_DEVICE_PATH *Fibre; + + Fibre = DevPath; + CatPrint (Str, L"Fibre(Wwn%lx,Lun%x)", Fibre->WWN, Fibre->Lun); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPath1394 ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + F1394_DEVICE_PATH *F1394Path; + + F1394Path = DevPath; + CatPrint (Str, L"1394(%lx)", &F1394Path->Guid); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathUsb ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + USB_DEVICE_PATH *Usb; + + Usb = DevPath; + CatPrint (Str, L"Usb(%x,%x)", (UINTN) Usb->ParentPortNumber, (UINTN) Usb->InterfaceNumber); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathUsbWWID ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + USB_WWID_DEVICE_PATH *UsbWWId; + + UsbWWId = DevPath; + CatPrint ( + Str, + L"UsbWwid(%x,%x,%x,\"WWID\")", + (UINTN) UsbWWId->VendorId, + (UINTN) UsbWWId->ProductId, + (UINTN) UsbWWId->InterfaceNumber + ); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathLogicalUnit ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + DEVICE_LOGICAL_UNIT_DEVICE_PATH *LogicalUnit; + + LogicalUnit = DevPath; + CatPrint (Str, L"Unit(%x)", (UINTN) LogicalUnit->Lun); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathUsbClass ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + USB_CLASS_DEVICE_PATH *UsbClass; + + UsbClass = DevPath; + CatPrint ( + Str, + L"Usb Class(%x,%x,%x,%x,%x)", + (UINTN) UsbClass->VendorId, + (UINTN) UsbClass->ProductId, + (UINTN) UsbClass->DeviceClass, + (UINTN) UsbClass->DeviceSubClass, + (UINTN) UsbClass->DeviceProtocol + ); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathSata ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + SATA_DEVICE_PATH *Sata; + + Sata = DevPath; + if ((Sata->PortMultiplierPortNumber & SATA_HBA_DIRECT_CONNECT_FLAG) != 0) { + CatPrint ( + Str, + L"Sata(%x,%x)", + (UINTN) Sata->HBAPortNumber, + (UINTN) Sata->Lun + ); + } else { + CatPrint ( + Str, + L"Sata(%x,%x,%x)", + (UINTN) Sata->HBAPortNumber, + (UINTN) Sata->PortMultiplierPortNumber, + (UINTN) Sata->Lun + ); + } +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathI2O ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + I2O_DEVICE_PATH *I2OPath; + + I2OPath = DevPath; + CatPrint (Str, L"I2O(%x)", (UINTN) I2OPath->Tid); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathMacAddr ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + MAC_ADDR_DEVICE_PATH *MACDevPath; + UINTN HwAddressSize; + UINTN Index; + + MACDevPath = DevPath; + + HwAddressSize = sizeof (EFI_MAC_ADDRESS); + if (MACDevPath->IfType == 0x01 || MACDevPath->IfType == 0x00) { + HwAddressSize = 6; + } + + CatPrint (Str, L"Mac("); + + for (Index = 0; Index < HwAddressSize; Index++) { + CatPrint (Str, L"%02x", (UINTN) MACDevPath->MacAddress.Addr[Index]); + } + + CatPrint (Str, L")"); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathIPv4 ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + IPv4_DEVICE_PATH *IPDevPath; + + IPDevPath = DevPath; + CatPrint ( + Str, + L"IPv4(%d.%d.%d.%d:%d)", + (UINTN) IPDevPath->RemoteIpAddress.Addr[0], + (UINTN) IPDevPath->RemoteIpAddress.Addr[1], + (UINTN) IPDevPath->RemoteIpAddress.Addr[2], + (UINTN) IPDevPath->RemoteIpAddress.Addr[3], + (UINTN) IPDevPath->RemotePort + ); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathIPv6 ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + IPv6_DEVICE_PATH *IPv6DevPath; + + IPv6DevPath = DevPath; + CatPrint ( + Str, + L"IPv6(%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x)", + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[0], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[1], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[2], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[3], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[4], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[5], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[6], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[7], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[8], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[9], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[10], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[11], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[12], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[13], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[14], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[15] + ); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathInfiniBand ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + INFINIBAND_DEVICE_PATH *InfiniBand; + + InfiniBand = DevPath; + CatPrint ( + Str, + L"Infiniband(%x,%g,%lx,%lx,%lx)", + (UINTN) InfiniBand->ResourceFlags, + InfiniBand->PortGid, + InfiniBand->ServiceId, + InfiniBand->TargetPortId, + InfiniBand->DeviceId + ); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathUart ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + UART_DEVICE_PATH *Uart; + CHAR8 Parity; + + Uart = DevPath; + switch (Uart->Parity) { + case 0: + Parity = 'D'; + break; + + case 1: + Parity = 'N'; + break; + + case 2: + Parity = 'E'; + break; + + case 3: + Parity = 'O'; + break; + + case 4: + Parity = 'M'; + break; + + case 5: + Parity = 'S'; + break; + + default: + Parity = 'x'; + break; + } + + if (Uart->BaudRate == 0) { + CatPrint (Str, L"Uart(DEFAULT,%c,", Parity); + } else { + CatPrint (Str, L"Uart(%ld,%c,", Uart->BaudRate, Parity); + } + + if (Uart->DataBits == 0) { + CatPrint (Str, L"D,"); + } else { + CatPrint (Str, L"%d,", (UINTN) Uart->DataBits); + } + + switch (Uart->StopBits) { + case 0: + CatPrint (Str, L"D)"); + break; + + case 1: + CatPrint (Str, L"1)"); + break; + + case 2: + CatPrint (Str, L"1.5)"); + break; + + case 3: + CatPrint (Str, L"2)"); + break; + + default: + CatPrint (Str, L"x)"); + break; + } +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathiSCSI ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + ISCSI_DEVICE_PATH_WITH_NAME *IScsi; + UINT16 Options; + + IScsi = DevPath; + CatPrint ( + Str, + L"iSCSI(%a,%x,%lx,", + IScsi->TargetName, + (UINTN) IScsi->TargetPortalGroupTag, + IScsi->Lun + ); + + Options = IScsi->LoginOption; + CatPrint (Str, L"%s,", (((Options >> 1) & 0x0001) != 0) ? L"CRC32C" : L"None"); + CatPrint (Str, L"%s,", (((Options >> 3) & 0x0001) != 0) ? L"CRC32C" : L"None"); + if (((Options >> 11) & 0x0001) != 0) { + CatPrint (Str, L"%s,", L"None"); + } else if (((Options >> 12) & 0x0001) != 0) { + CatPrint (Str, L"%s,", L"CHAP_UNI"); + } else { + CatPrint (Str, L"%s,", L"CHAP_BI"); + + } + + CatPrint (Str, L"%s)", (IScsi->NetworkProtocol == 0) ? L"TCP" : L"reserved"); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathVlan ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + VLAN_DEVICE_PATH *Vlan; + + Vlan = DevPath; + CatPrint (Str, L"Vlan(%d)", (UINTN) Vlan->VlanId); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathHardDrive ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + HARDDRIVE_DEVICE_PATH *Hd; + + Hd = DevPath; + switch (Hd->SignatureType) { + case SIGNATURE_TYPE_MBR: + CatPrint ( + Str, + L"HD(Part%d,Sig%08x)", + (UINTN) Hd->PartitionNumber, + (UINTN) *((UINT32 *) (&(Hd->Signature[0]))) + ); + break; + + case SIGNATURE_TYPE_GUID: + CatPrint ( + Str, + L"HD(Part%d,Sig%g)", + (UINTN) Hd->PartitionNumber, + (EFI_GUID *) &(Hd->Signature[0]) + ); + break; + + default: + CatPrint ( + Str, + L"HD(Part%d,MBRType=%02x,SigType=%02x)", + (UINTN) Hd->PartitionNumber, + (UINTN) Hd->MBRType, + (UINTN) Hd->SignatureType + ); + break; + } +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathCDROM ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + CDROM_DEVICE_PATH *Cd; + + Cd = DevPath; + CatPrint (Str, L"CDROM(Entry%x)", (UINTN) Cd->BootEntry); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathFilePath ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + FILEPATH_DEVICE_PATH *Fp; + + Fp = DevPath; + CatPrint (Str, L"%s", Fp->PathName); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathMediaProtocol ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + MEDIA_PROTOCOL_DEVICE_PATH *MediaProt; + + MediaProt = DevPath; + CatPrint (Str, L"Media(%g)", &MediaProt->Protocol); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathFvFilePath ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFilePath; + + FvFilePath = DevPath; + CatPrint (Str, L"%g", &FvFilePath->FvFileName); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathRelativeOffsetRange ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH *Offset; + + Offset = DevPath; + CatPrint ( + Str, + L"Offset(%lx,%lx)", + Offset->StartingOffset, + Offset->EndingOffset + ); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathBssBss ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + BBS_BBS_DEVICE_PATH *Bbs; + CHAR16 *Type; + + Bbs = DevPath; + switch (Bbs->DeviceType) { + case BBS_TYPE_FLOPPY: + Type = L"Floppy"; + break; + + case BBS_TYPE_HARDDRIVE: + Type = L"Harddrive"; + break; + + case BBS_TYPE_CDROM: + Type = L"CDROM"; + break; + + case BBS_TYPE_PCMCIA: + Type = L"PCMCIA"; + break; + + case BBS_TYPE_USB: + Type = L"Usb"; + break; + + case BBS_TYPE_EMBEDDED_NETWORK: + Type = L"Net"; + break; + + case BBS_TYPE_BEV: + Type = L"BEV"; + break; + + default: + Type = L"?"; + break; + } + CatPrint (Str, L"Legacy-%s", Type); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathEndInstance ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + CatPrint (Str, L","); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathNodeUnknown ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + CatPrint (Str, L"?"); +} +/** + Convert Device Path to a Unicode string for printing. + + @param[in, out] Str The buffer holding the output string. + This buffer contains the length of the string and + the maixmum length reserved for the string buffer. + @param[in] DevPath The device path. + +**/ +VOID +DevPathFvPath ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + MEDIA_FW_VOL_DEVICE_PATH *FvPath; + + FvPath = DevPath; + CatPrint (Str, L"Fv(%g)", &FvPath->FvName); +} + +DEVICE_PATH_STRING_TABLE DevPathTable[] = { + { + HARDWARE_DEVICE_PATH, + HW_PCI_DP, + DevPathPci + }, + { + HARDWARE_DEVICE_PATH, + HW_PCCARD_DP, + DevPathPccard + }, + { + HARDWARE_DEVICE_PATH, + HW_MEMMAP_DP, + DevPathMemMap + }, + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + DevPathVendor + }, + { + HARDWARE_DEVICE_PATH, + HW_CONTROLLER_DP, + DevPathController + }, + { + ACPI_DEVICE_PATH, + ACPI_DP, + DevPathAcpi + }, + { + ACPI_DEVICE_PATH, + ACPI_EXTENDED_DP, + DevPathExtendedAcpi + }, + { + ACPI_DEVICE_PATH, + ACPI_ADR_DP, + DevPathAdrAcpi + }, + { + MESSAGING_DEVICE_PATH, + MSG_ATAPI_DP, + DevPathAtapi + }, + { + MESSAGING_DEVICE_PATH, + MSG_SCSI_DP, + DevPathScsi + }, + { + MESSAGING_DEVICE_PATH, + MSG_FIBRECHANNEL_DP, + DevPathFibre + }, + { + MESSAGING_DEVICE_PATH, + MSG_1394_DP, + DevPath1394 + }, + { + MESSAGING_DEVICE_PATH, + MSG_USB_DP, + DevPathUsb + }, + { + MESSAGING_DEVICE_PATH, + MSG_USB_WWID_DP, + DevPathUsbWWID + }, + { + MESSAGING_DEVICE_PATH, + MSG_DEVICE_LOGICAL_UNIT_DP, + DevPathLogicalUnit + }, + { + MESSAGING_DEVICE_PATH, + MSG_USB_CLASS_DP, + DevPathUsbClass + }, + { + MESSAGING_DEVICE_PATH, + MSG_SATA_DP, + DevPathSata + }, + { + MESSAGING_DEVICE_PATH, + MSG_I2O_DP, + DevPathI2O + }, + { + MESSAGING_DEVICE_PATH, + MSG_MAC_ADDR_DP, + DevPathMacAddr + }, + { + MESSAGING_DEVICE_PATH, + MSG_IPv4_DP, + DevPathIPv4 + }, + { + MESSAGING_DEVICE_PATH, + MSG_IPv6_DP, + DevPathIPv6 + }, + { + MESSAGING_DEVICE_PATH, + MSG_INFINIBAND_DP, + DevPathInfiniBand + }, + { + MESSAGING_DEVICE_PATH, + MSG_UART_DP, + DevPathUart + }, + { + MESSAGING_DEVICE_PATH, + MSG_VENDOR_DP, + DevPathVendor + }, + { + MESSAGING_DEVICE_PATH, + MSG_ISCSI_DP, + DevPathiSCSI + }, + { + MESSAGING_DEVICE_PATH, + MSG_VLAN_DP, + DevPathVlan + }, + { + MEDIA_DEVICE_PATH, + MEDIA_HARDDRIVE_DP, + DevPathHardDrive + }, + { + MEDIA_DEVICE_PATH, + MEDIA_CDROM_DP, + DevPathCDROM + }, + { + MEDIA_DEVICE_PATH, + MEDIA_VENDOR_DP, + DevPathVendor + }, + { + MEDIA_DEVICE_PATH, + MEDIA_FILEPATH_DP, + DevPathFilePath + }, + { + MEDIA_DEVICE_PATH, + MEDIA_PROTOCOL_DP, + DevPathMediaProtocol + }, + { + MEDIA_DEVICE_PATH, + MEDIA_PIWG_FW_VOL_DP, + DevPathFvPath, + }, + { + MEDIA_DEVICE_PATH, + MEDIA_PIWG_FW_FILE_DP, + DevPathFvFilePath + }, + { + MEDIA_DEVICE_PATH, + MEDIA_RELATIVE_OFFSET_RANGE_DP, + DevPathRelativeOffsetRange, + }, + { + BBS_DEVICE_PATH, + BBS_BBS_DP, + DevPathBssBss + }, + { + END_DEVICE_PATH_TYPE, + END_INSTANCE_DEVICE_PATH_SUBTYPE, + DevPathEndInstance + }, + { + 0, + 0, + NULL + } +}; + + +/** + This function converts an input device structure to a Unicode string. + + @param[in] DevPath A pointer to the device path structure. + + @return A new allocated Unicode string that represents the device path. + +**/ +CHAR16 * +EFIAPI +DevicePathToStr ( + IN EFI_DEVICE_PATH_PROTOCOL *DevPath + ) +{ + POOL_PRINT Str; + EFI_DEVICE_PATH_PROTOCOL *DevPathNode; + VOID (*DumpNode) (POOL_PRINT *, VOID *); + + UINTN Index; + UINTN NewSize; + + EFI_STATUS Status; + CHAR16 *ToText; + EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText; + + ZeroMem (&Str, sizeof (Str)); + + if (DevPath == NULL) { + goto Done; + } + + Status = gBS->LocateProtocol ( + &gEfiDevicePathToTextProtocolGuid, + NULL, + (VOID **) &DevPathToText + ); + if (!EFI_ERROR (Status)) { + ToText = DevPathToText->ConvertDevicePathToText ( + DevPath, + FALSE, + TRUE + ); + ASSERT (ToText != NULL); + return ToText; + } + + // + // Process each device path node + // + DevPathNode = DevPath; + while (!IsDevicePathEnd (DevPathNode)) { + // + // Find the handler to dump this device path node + // + DumpNode = NULL; + for (Index = 0; DevPathTable[Index].Function != NULL; Index += 1) { + + if (DevicePathType (DevPathNode) == DevPathTable[Index].Type && + DevicePathSubType (DevPathNode) == DevPathTable[Index].SubType + ) { + DumpNode = DevPathTable[Index].Function; + break; + } + } + // + // If not found, use a generic function + // + if (!DumpNode) { + DumpNode = DevPathNodeUnknown; + } + // + // Put a path seperator in if needed + // + if ((Str.Len != 0) && (DumpNode != DevPathEndInstance)) { + CatPrint (&Str, L"/"); + } + // + // Print this node of the device path + // + DumpNode (&Str, DevPathNode); + + // + // Next device path node + // + DevPathNode = NextDevicePathNode (DevPathNode); + } + +Done: + NewSize = (Str.Len + 1) * sizeof (CHAR16); + Str.Str = ReallocatePool (NewSize, NewSize, Str.Str); + ASSERT (Str.Str != NULL); + Str.Str[Str.Len] = 0; + return Str.Str; +} + diff --git a/OvmfPkg/SecureBootConfigDxe/SecureBootConfigDriver.c b/OvmfPkg/SecureBootConfigDxe/SecureBootConfigDriver.c new file mode 100644 index 0000000000..1d6c4ac6e8 --- /dev/null +++ b/OvmfPkg/SecureBootConfigDxe/SecureBootConfigDriver.c @@ -0,0 +1,133 @@ +/** @file + The module entry point for SecureBoot configuration module. + +Copyright (c) 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "SecureBootConfigImpl.h" + +/** + The entry point for SecureBoot configuration driver. + + @param[in] ImageHandle The image handle of the driver. + @param[in] SystemTable The system table. + + @retval EFI_ALREADY_STARTED The driver already exists in system. + @retval EFI_OUT_OF_RESOURCES Fail to execute entry point due to lack of resources. + @retval EFI_SUCCES All the related protocols are installed on the driver. + @retval Others Fail to get the SecureBootEnable variable. + +**/ +EFI_STATUS +EFIAPI +SecureBootConfigDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData; + + // + // If already started, return. + // + Status = gBS->OpenProtocol ( + ImageHandle, + &gEfiCallerIdGuid, + NULL, + ImageHandle, + ImageHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + return EFI_ALREADY_STARTED; + } + + // + // Create a private data structure. + // + PrivateData = AllocateCopyPool (sizeof (SECUREBOOT_CONFIG_PRIVATE_DATA), &mSecureBootConfigPrivateDateTemplate); + if (PrivateData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Install SecureBoot configuration form + // + Status = InstallSecureBootConfigForm (PrivateData); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + // + // Install private GUID. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiCallerIdGuid, + PrivateData, + NULL + ); + + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + return EFI_SUCCESS; + +ErrorExit: + if (PrivateData != NULL) { + UninstallSecureBootConfigForm (PrivateData); + } + + return Status; +} + +/** + Unload the SecureBoot configuration form. + + @param[in] ImageHandle The driver's image handle. + + @retval EFI_SUCCESS The SecureBoot configuration form is unloaded. + @retval Others Failed to unload the form. + +**/ +EFI_STATUS +EFIAPI +SecureBootConfigDriverUnload ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData; + + Status = gBS->HandleProtocol ( + ImageHandle, + &gEfiCallerIdGuid, + (VOID **) &PrivateData + ); + if (EFI_ERROR (Status)) { + return Status; + } + + ASSERT (PrivateData->Signature == SECUREBOOT_CONFIG_PRIVATE_DATA_SIGNATURE); + + gBS->UninstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiCallerIdGuid, + PrivateData, + NULL + ); + + UninstallSecureBootConfigForm (PrivateData); + + return EFI_SUCCESS; +} diff --git a/OvmfPkg/SecureBootConfigDxe/SecureBootConfigDxe.inf b/OvmfPkg/SecureBootConfigDxe/SecureBootConfigDxe.inf new file mode 100644 index 0000000000..44b15b8eb1 --- /dev/null +++ b/OvmfPkg/SecureBootConfigDxe/SecureBootConfigDxe.inf @@ -0,0 +1,105 @@ +## @file +# Component name for SecureBoot configuration module for OVMF. +# +# Need custom SecureBootConfigDxe for OVMF that does not force +# resets after PK changes since OVMF doesn't have persistent variables +# +# Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SecureBootConfigDxe + FILE_GUID = F0E6A44F-7195-41c3-AC64-54F202CD0A21 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = SecureBootConfigDriverEntryPoint + UNLOAD_IMAGE = SecureBootConfigDriverUnload + +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + SecureBootConfigDriver.c + SecureBootConfigImpl.c + SecureBootConfigFileExplorer.c + SecureBootConfigDevicePath.c + SecureBootConfigMisc.c + SecureBootConfigImpl.h + SecureBootConfig.vfr + SecureBootConfigStrings.uni + SecureBootConfigNvData.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + CryptoPkg/CryptoPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + BaseCryptLib + MemoryAllocationLib + UefiLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + UefiDriverEntryPoint + UefiHiiServicesLib + DebugLib + HiiLib + PlatformSecureLib + +[Guids] + gEfiIfrTianoGuid + gEfiCustomModeEnableGuid + gEfiSecureBootEnableDisableGuid + gSecureBootConfigFormSetGuid + gEfiCertPkcs7Guid + gEfiCertRsa2048Guid ## CONSUMES + gEfiCertX509Guid ## CONSUMES + gEfiCertSha1Guid ## CONSUMES + gEfiCertSha256Guid ## CONSUMES + gEfiCertTypeRsa2048Sha256Guid ## CONSUMES + gEfiImageSecurityDatabaseGuid ## CONSUMES + gEfiFileSystemVolumeLabelInfoIdGuid ## CONSUMES + gEfiGlobalVariableGuid ## PRODUCES ## Variable Guid + gEfiVT100PlusGuid ## CONSUMES ## GUID (The type of terminal) + gEfiVT100Guid ## CONSUMES ## GUID (The type of terminal) + ## CONSUMES ## GUID HOB (The hob holding memory type information) + gEfiVTUTF8Guid ## CONSUMES ## GUID (The type of terminal) + ## SOMETIMES_CONSUMES ## Variable:L"BootXX" (Boot option variable) + ## CONSUMES ## Variable:L"Timeout" (The time out value in second of showing progress bar) + ## SOMETIMES_CONSUMES ## Variable:L"BootOrder" (The boot option array) + ## SOMETIMES_CONSUMES ## Variable:L"DriverOrder" (The driver order list) + ## SOMETIMES_CONSUMES ## Variable:L"ConIn" (The device path of console in device) + ## SOMETIMES_CONSUMES ## Variable:L"ConOut" (The device path of console out device) + ## SOMETIMES_CONSUMES ## Variable:L"ErrOut" (The device path of error out device) + gEfiFileInfoGuid ## CONSUMES ## GUID + gEfiPcAnsiGuid ## CONSUMES ## GUID (The type of terminal) + gEfiUartDevicePathGuid ## CONSUMES ## GUID (Identify the device path for UARD device) + gEfiSasDevicePathGuid ## CONSUMES ## GUID (Identify the device path for SAS device) + +[Protocols] + gEfiHiiConfigAccessProtocolGuid ## PRODUCES + gEfiHiiConfigRoutingProtocolGuid ## CONSUMES + gEfiSimpleFileSystemProtocolGuid ## PROTOCOL CONSUMES + gEfiLoadFileProtocolGuid ## PROTOCOL CONSUMES + gEfiBlockIoProtocolGuid ## PROTOCOL CONSUMES + gEfiDevicePathProtocolGuid ## PROTOCOL CONSUMES + gEfiDevicePathToTextProtocolGuid + gEfiDebugPortProtocolGuid + +[Depex] + gEfiHiiConfigRoutingProtocolGuid AND + gEfiHiiDatabaseProtocolGuid AND + gEfiVariableArchProtocolGuid AND + gEfiVariableWriteArchProtocolGuid diff --git a/OvmfPkg/SecureBootConfigDxe/SecureBootConfigFileExplorer.c b/OvmfPkg/SecureBootConfigDxe/SecureBootConfigFileExplorer.c new file mode 100644 index 0000000000..deff87bcbd --- /dev/null +++ b/OvmfPkg/SecureBootConfigDxe/SecureBootConfigFileExplorer.c @@ -0,0 +1,1227 @@ +/** @file + Internal file explorer functions for SecureBoot configuration module. + +Copyright (c) 2012, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "SecureBootConfigImpl.h" + +/// +/// File system selection menu +/// +SECUREBOOT_MENU_OPTION FsOptionMenu = { + SECUREBOOT_MENU_OPTION_SIGNATURE, + {NULL}, + 0 +}; + +/// +/// Files and sub-directories in current directory menu +/// +SECUREBOOT_MENU_OPTION DirectoryMenu = { + SECUREBOOT_MENU_OPTION_SIGNATURE, + {NULL}, + 0 +}; + +VOID *mStartOpCodeHandle = NULL; +VOID *mEndOpCodeHandle = NULL; +EFI_IFR_GUID_LABEL *mStartLabel = NULL; +EFI_IFR_GUID_LABEL *mEndLabel = NULL; + +/** + Duplicate a string. + + @param[in] Src The source string. + + @return A new string which is duplicated copy of the source, + or NULL if there is not enough memory. + +**/ +CHAR16 * +StrDuplicate ( + IN CHAR16 *Src + ) +{ + CHAR16 *Dest; + UINTN Size; + + Size = StrSize (Src); + Dest = AllocateZeroPool (Size); + ASSERT (Dest != NULL); + if (Dest != NULL) { + CopyMem (Dest, Src, Size); + } + + return Dest; +} + +/** + Helper function called as part of the code needed to allocate + the proper sized buffer for various EFI interfaces. + + @param[in, out] Status Current status + @param[in, out] Buffer Current allocated buffer, or NULL + @param[in] BufferSize Current buffer size needed + + @retval TRUE If the buffer was reallocated and the caller + should try the API again. + @retval FALSE The caller should not call this function again. + +**/ +BOOLEAN +GrowBuffer ( + IN OUT EFI_STATUS *Status, + IN OUT VOID **Buffer, + IN UINTN BufferSize + ) +{ + BOOLEAN TryAgain; + + // + // If this is an initial request, buffer will be null with a new buffer size + // + if ((*Buffer == NULL) && (BufferSize != 0)) { + *Status = EFI_BUFFER_TOO_SMALL; + } + // + // If the status code is "buffer too small", resize the buffer + // + TryAgain = FALSE; + if (*Status == EFI_BUFFER_TOO_SMALL) { + + if (*Buffer != NULL) { + FreePool (*Buffer); + } + + *Buffer = AllocateZeroPool (BufferSize); + + if (*Buffer != NULL) { + TryAgain = TRUE; + } else { + *Status = EFI_OUT_OF_RESOURCES; + } + } + // + // If there's an error, free the buffer + // + if (!TryAgain && EFI_ERROR (*Status) && (*Buffer != NULL)) { + FreePool (*Buffer); + *Buffer = NULL; + } + + return TryAgain; +} + +/** + Append file name to existing file name, and allocate a new buffer + to hold the appended result. + + @param[in] Str1 The existing file name + @param[in] Str2 The file name to be appended + + @return A new string with appended result. + +**/ +CHAR16 * +AppendFileName ( + IN CHAR16 *Str1, + IN CHAR16 *Str2 + ) +{ + UINTN Size1; + UINTN Size2; + CHAR16 *Str; + CHAR16 *TmpStr; + CHAR16 *Ptr; + CHAR16 *LastSlash; + + Size1 = StrSize (Str1); + Size2 = StrSize (Str2); + Str = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16)); + ASSERT (Str != NULL); + + TmpStr = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16)); + ASSERT (TmpStr != NULL); + + StrCat (Str, Str1); + if (!((*Str == '\\') && (*(Str + 1) == 0))) { + StrCat (Str, L"\\"); + } + + StrCat (Str, Str2); + + Ptr = Str; + LastSlash = Str; + while (*Ptr != 0) { + if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) == L'\\') { + // + // Convert "\Name\..\" to "\" + // DO NOT convert the .. if it is at the end of the string. This will + // break the .. behavior in changing directories. + // + + // + // Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings + // that overlap. + // + StrCpy (TmpStr, Ptr + 3); + StrCpy (LastSlash, TmpStr); + Ptr = LastSlash; + } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') { + // + // Convert a "\.\" to a "\" + // + + // + // Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings + // that overlap. + // + StrCpy (TmpStr, Ptr + 2); + StrCpy (Ptr, TmpStr); + Ptr = LastSlash; + } else if (*Ptr == '\\') { + LastSlash = Ptr; + } + + Ptr++; + } + + FreePool (TmpStr); + + return Str; +} + +/** + Create a SECUREBOOT_MENU_ENTRY, and stores it in a buffer allocated from the pool. + + @return The new menu entry or NULL of error happens. + +**/ +SECUREBOOT_MENU_ENTRY * +CreateMenuEntry ( + VOID + ) +{ + SECUREBOOT_MENU_ENTRY *MenuEntry; + UINTN ContextSize; + + // + // Create new menu entry + // + MenuEntry = AllocateZeroPool (sizeof (SECUREBOOT_MENU_ENTRY)); + if (MenuEntry == NULL) { + return NULL; + } + + ContextSize = sizeof (SECUREBOOT_FILE_CONTEXT); + MenuEntry->FileContext = AllocateZeroPool (ContextSize); + if (MenuEntry->FileContext == NULL) { + FreePool (MenuEntry); + return NULL; + } + + MenuEntry->Signature = SECUREBOOT_MENU_ENTRY_SIGNATURE; + + return MenuEntry; +} + +/** + Get Menu Entry from the Menu Entry List by MenuNumber. + + If MenuNumber is great or equal to the number of Menu + Entry in the list, then ASSERT. + + @param[in] MenuOption The Menu Entry List to read the menu entry. + @param[in] MenuNumber The index of Menu Entry. + + @return The Menu Entry. + +**/ +SECUREBOOT_MENU_ENTRY * +GetMenuEntry ( + IN SECUREBOOT_MENU_OPTION *MenuOption, + IN UINTN MenuNumber + ) +{ + SECUREBOOT_MENU_ENTRY *NewMenuEntry; + UINTN Index; + LIST_ENTRY *List; + + ASSERT (MenuNumber < MenuOption->MenuNumber); + + List = MenuOption->Head.ForwardLink; + for (Index = 0; Index < MenuNumber; Index++) { + List = List->ForwardLink; + } + + NewMenuEntry = CR (List, SECUREBOOT_MENU_ENTRY, Link, SECUREBOOT_MENU_ENTRY_SIGNATURE); + + return NewMenuEntry; +} + +/** + Create string tokens for a menu from its help strings and display strings. + + @param[in] HiiHandle Hii Handle of the package to be updated. + @param[in] MenuOption The Menu whose string tokens need to be created. + +**/ +VOID +CreateMenuStringToken ( + IN EFI_HII_HANDLE HiiHandle, + IN SECUREBOOT_MENU_OPTION *MenuOption + ) +{ + SECUREBOOT_MENU_ENTRY *NewMenuEntry; + UINTN Index; + + for (Index = 0; Index < MenuOption->MenuNumber; Index++) { + NewMenuEntry = GetMenuEntry (MenuOption, Index); + + NewMenuEntry->DisplayStringToken = HiiSetString ( + HiiHandle, + 0, + NewMenuEntry->DisplayString, + NULL + ); + + if (NewMenuEntry->HelpString == NULL) { + NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken; + } else { + NewMenuEntry->HelpStringToken = HiiSetString ( + HiiHandle, + 0, + NewMenuEntry->HelpString, + NULL + ); + } + } +} + +/** + Free up all resources allocated for a SECUREBOOT_MENU_ENTRY. + + @param[in, out] MenuEntry A pointer to SECUREBOOT_MENU_ENTRY. + +**/ +VOID +DestroyMenuEntry ( + IN OUT SECUREBOOT_MENU_ENTRY *MenuEntry + ) +{ + SECUREBOOT_FILE_CONTEXT *FileContext; + + + FileContext = (SECUREBOOT_FILE_CONTEXT *) MenuEntry->FileContext; + + if (!FileContext->IsRoot) { + FreePool (FileContext->DevicePath); + } else { + if (FileContext->FHandle != NULL) { + FileContext->FHandle->Close (FileContext->FHandle); + } + } + + if (FileContext->FileName != NULL) { + FreePool (FileContext->FileName); + } + if (FileContext->Info != NULL) { + FreePool (FileContext->Info); + } + + FreePool (FileContext); + + FreePool (MenuEntry->DisplayString); + if (MenuEntry->HelpString != NULL) { + FreePool (MenuEntry->HelpString); + } + + FreePool (MenuEntry); +} + +/** + Free resources allocated in Allocate Rountine. + + @param[in, out] MenuOption Menu to be freed + +**/ +VOID +FreeMenu ( + IN OUT SECUREBOOT_MENU_OPTION *MenuOption + ) +{ + SECUREBOOT_MENU_ENTRY *MenuEntry; + while (!IsListEmpty (&MenuOption->Head)) { + MenuEntry = CR ( + MenuOption->Head.ForwardLink, + SECUREBOOT_MENU_ENTRY, + Link, + SECUREBOOT_MENU_ENTRY_SIGNATURE + ); + RemoveEntryList (&MenuEntry->Link); + DestroyMenuEntry (MenuEntry); + } + MenuOption->MenuNumber = 0; +} + +/** + This function gets the file information from an open file descriptor, and stores it + in a buffer allocated from pool. + + @param[in] FHand File Handle. + + @return A pointer to a buffer with file information or NULL is returned + +**/ +EFI_FILE_INFO * +FileInfo ( + IN EFI_FILE_HANDLE FHand + ) +{ + EFI_STATUS Status; + EFI_FILE_INFO *Buffer; + UINTN BufferSize; + + // + // Initialize for GrowBuffer loop + // + Buffer = NULL; + BufferSize = SIZE_OF_EFI_FILE_INFO + 200; + + // + // Call the real function + // + while (GrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) { + Status = FHand->GetInfo ( + FHand, + &gEfiFileInfoGuid, + &BufferSize, + Buffer + ); + } + + return Buffer; +} + +/** + This function gets the file system information from an open file descriptor, + and stores it in a buffer allocated from pool. + + @param[in] FHand The file handle. + + @return A pointer to a buffer with file information. + @retval NULL is returned if failed to get Vaolume Label Info. + +**/ +EFI_FILE_SYSTEM_VOLUME_LABEL * +FileSystemVolumeLabelInfo ( + IN EFI_FILE_HANDLE FHand + ) +{ + EFI_STATUS Status; + EFI_FILE_SYSTEM_VOLUME_LABEL *Buffer; + UINTN BufferSize; + // + // Initialize for GrowBuffer loop + // + Buffer = NULL; + BufferSize = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL + 200; + + // + // Call the real function + // + while (GrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) { + Status = FHand->GetInfo ( + FHand, + &gEfiFileSystemVolumeLabelInfoIdGuid, + &BufferSize, + Buffer + ); + } + + return Buffer; +} + +/** + This function will open a file or directory referenced by DevicePath. + + This function opens a file with the open mode according to the file path. The + Attributes is valid only for EFI_FILE_MODE_CREATE. + + @param[in, out] FilePath On input, the device path to the file. + On output, the remaining device path. + @param[out] FileHandle Pointer to the file handle. + @param[in] OpenMode The mode to open the file with. + @param[in] Attributes The file's file attributes. + + @retval EFI_SUCCESS The information was set. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. + @retval EFI_UNSUPPORTED Could not open the file path. + @retval EFI_NOT_FOUND The specified file could not be found on the + device or the file system could not be found on + the device. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_MEDIA_CHANGED The device has a different medium in it or the + medium is no longer supported. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The file or medium is write protected. + @retval EFI_ACCESS_DENIED The file was opened read only. + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the + file. + @retval EFI_VOLUME_FULL The volume is full. +**/ +EFI_STATUS +EFIAPI +OpenFileByDevicePath( + IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath, + OUT EFI_FILE_HANDLE *FileHandle, + IN UINT64 OpenMode, + IN UINT64 Attributes + ) +{ + EFI_STATUS Status; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *EfiSimpleFileSystemProtocol; + EFI_FILE_PROTOCOL *Handle1; + EFI_FILE_PROTOCOL *Handle2; + EFI_HANDLE DeviceHandle; + + if ((FilePath == NULL || FileHandle == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Status = gBS->LocateDevicePath ( + &gEfiSimpleFileSystemProtocolGuid, + FilePath, + &DeviceHandle + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->OpenProtocol( + DeviceHandle, + &gEfiSimpleFileSystemProtocolGuid, + (VOID**)&EfiSimpleFileSystemProtocol, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = EfiSimpleFileSystemProtocol->OpenVolume(EfiSimpleFileSystemProtocol, &Handle1); + if (EFI_ERROR (Status)) { + FileHandle = NULL; + return Status; + } + + // + // go down directories one node at a time. + // + while (!IsDevicePathEnd (*FilePath)) { + // + // For file system access each node should be a file path component + // + if (DevicePathType (*FilePath) != MEDIA_DEVICE_PATH || + DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP + ) { + FileHandle = NULL; + return (EFI_INVALID_PARAMETER); + } + // + // Open this file path node + // + Handle2 = Handle1; + Handle1 = NULL; + + // + // Try to test opening an existing file + // + Status = Handle2->Open ( + Handle2, + &Handle1, + ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName, + OpenMode &~EFI_FILE_MODE_CREATE, + 0 + ); + + // + // see if the error was that it needs to be created + // + if ((EFI_ERROR (Status)) && (OpenMode != (OpenMode &~EFI_FILE_MODE_CREATE))) { + Status = Handle2->Open ( + Handle2, + &Handle1, + ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName, + OpenMode, + Attributes + ); + } + // + // Close the last node + // + Handle2->Close (Handle2); + + if (EFI_ERROR(Status)) { + return (Status); + } + + // + // Get the next node + // + *FilePath = NextDevicePathNode (*FilePath); + } + + // + // This is a weak spot since if the undefined SHELL_FILE_HANDLE format changes this must change also! + // + *FileHandle = (VOID*)Handle1; + return EFI_SUCCESS; +} + +/** + Function opens and returns a file handle to the root directory of a volume. + + @param[in] DeviceHandle A handle for a device + + @return A valid file handle or NULL if error happens. + +**/ +EFI_FILE_HANDLE +OpenRoot ( + IN EFI_HANDLE DeviceHandle + ) +{ + EFI_STATUS Status; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume; + EFI_FILE_HANDLE File; + + File = NULL; + + // + // File the file system interface to the device + // + Status = gBS->HandleProtocol ( + DeviceHandle, + &gEfiSimpleFileSystemProtocolGuid, + (VOID *) &Volume + ); + + // + // Open the root directory of the volume + // + if (!EFI_ERROR (Status)) { + Status = Volume->OpenVolume ( + Volume, + &File + ); + } + // + // Done + // + return EFI_ERROR (Status) ? NULL : File; +} + +/** + This function builds the FsOptionMenu list which records all + available file system in the system. They include all instances + of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM + and all type of legacy boot device. + + @retval EFI_SUCCESS Success find the file system + @retval EFI_OUT_OF_RESOURCES Can not create menu entry + +**/ +EFI_STATUS +FindFileSystem ( + VOID + ) +{ + UINTN NoBlkIoHandles; + UINTN NoSimpleFsHandles; + UINTN NoLoadFileHandles; + EFI_HANDLE *BlkIoHandle; + EFI_HANDLE *SimpleFsHandle; + UINT16 *VolumeLabel; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + UINTN Index; + EFI_STATUS Status; + SECUREBOOT_MENU_ENTRY *MenuEntry; + SECUREBOOT_FILE_CONTEXT *FileContext; + UINT16 *TempStr; + UINTN OptionNumber; + VOID *Buffer; + + BOOLEAN RemovableMedia; + + + NoSimpleFsHandles = 0; + NoLoadFileHandles = 0; + OptionNumber = 0; + InitializeListHead (&FsOptionMenu.Head); + + // + // Locate Handles that support BlockIo protocol + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiBlockIoProtocolGuid, + NULL, + &NoBlkIoHandles, + &BlkIoHandle + ); + if (!EFI_ERROR (Status)) { + + for (Index = 0; Index < NoBlkIoHandles; Index++) { + Status = gBS->HandleProtocol ( + BlkIoHandle[Index], + &gEfiBlockIoProtocolGuid, + (VOID **) &BlkIo + ); + + if (EFI_ERROR (Status)) { + continue; + } + + // + // Issue a dummy read to trigger reinstall of BlockIo protocol for removable media + // + if (BlkIo->Media->RemovableMedia) { + Buffer = AllocateZeroPool (BlkIo->Media->BlockSize); + if (NULL == Buffer) { + FreePool (BlkIoHandle); + return EFI_OUT_OF_RESOURCES; + } + + BlkIo->ReadBlocks ( + BlkIo, + BlkIo->Media->MediaId, + 0, + BlkIo->Media->BlockSize, + Buffer + ); + FreePool (Buffer); + } + } + FreePool (BlkIoHandle); + } + + // + // Locate Handles that support Simple File System protocol + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimpleFileSystemProtocolGuid, + NULL, + &NoSimpleFsHandles, + &SimpleFsHandle + ); + if (!EFI_ERROR (Status)) { + // + // Find all the instances of the File System prototocol + // + for (Index = 0; Index < NoSimpleFsHandles; Index++) { + Status = gBS->HandleProtocol ( + SimpleFsHandle[Index], + &gEfiBlockIoProtocolGuid, + (VOID **) &BlkIo + ); + if (EFI_ERROR (Status)) { + // + // If no block IO exists assume it's NOT a removable media + // + RemovableMedia = FALSE; + } else { + // + // If block IO exists check to see if it's remobable media + // + RemovableMedia = BlkIo->Media->RemovableMedia; + } + + // + // Allocate pool for this instance. + // + MenuEntry = CreateMenuEntry (); + if (NULL == MenuEntry) { + FreePool (SimpleFsHandle); + return EFI_OUT_OF_RESOURCES; + } + + FileContext = (SECUREBOOT_FILE_CONTEXT *) MenuEntry->FileContext; + + FileContext->Handle = SimpleFsHandle[Index]; + MenuEntry->OptionNumber = Index; + FileContext->FHandle = OpenRoot (FileContext->Handle); + if (FileContext->FHandle == NULL) { + DestroyMenuEntry (MenuEntry); + continue; + } + + MenuEntry->HelpString = DevicePathToStr (DevicePathFromHandle (FileContext->Handle)); + FileContext->Info = FileSystemVolumeLabelInfo (FileContext->FHandle); + FileContext->FileName = StrDuplicate (L"\\"); + FileContext->DevicePath = FileDevicePath ( + FileContext->Handle, + FileContext->FileName + ); + FileContext->IsDir = TRUE; + FileContext->IsRoot = TRUE; + FileContext->IsRemovableMedia = RemovableMedia; + FileContext->IsLoadFile = FALSE; + + // + // Get current file system's Volume Label + // + if (FileContext->Info == NULL) { + VolumeLabel = L"NO FILE SYSTEM INFO"; + } else { + if (FileContext->Info->VolumeLabel == NULL) { + VolumeLabel = L"NULL VOLUME LABEL"; + } else { + VolumeLabel = FileContext->Info->VolumeLabel; + if (*VolumeLabel == 0x0000) { + VolumeLabel = L"NO VOLUME LABEL"; + } + } + } + + TempStr = MenuEntry->HelpString; + MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR); + ASSERT (MenuEntry->DisplayString != NULL); + UnicodeSPrint ( + MenuEntry->DisplayString, + MAX_CHAR, + L"%s, [%s]", + VolumeLabel, + TempStr + ); + OptionNumber++; + InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link); + } + } + + if (NoSimpleFsHandles != 0) { + FreePool (SimpleFsHandle); + } + + // + // Remember how many file system options are here + // + FsOptionMenu.MenuNumber = OptionNumber; + return EFI_SUCCESS; +} + + +/** + Find files under the current directory. All files and sub-directories + in current directory will be stored in DirectoryMenu for future use. + + @param[in] MenuEntry The Menu Entry. + + @retval EFI_SUCCESS Get files from current dir successfully. + @return Other Can't get files from current dir. + +**/ +EFI_STATUS +FindFiles ( + IN SECUREBOOT_MENU_ENTRY *MenuEntry + ) +{ + EFI_FILE_HANDLE NewDir; + EFI_FILE_HANDLE Dir; + EFI_FILE_INFO *DirInfo; + UINTN BufferSize; + UINTN DirBufferSize; + SECUREBOOT_MENU_ENTRY *NewMenuEntry; + SECUREBOOT_FILE_CONTEXT *FileContext; + SECUREBOOT_FILE_CONTEXT *NewFileContext; + UINTN Pass; + EFI_STATUS Status; + UINTN OptionNumber; + + FileContext = (SECUREBOOT_FILE_CONTEXT *) MenuEntry->FileContext; + Dir = FileContext->FHandle; + OptionNumber = 0; + // + // Open current directory to get files from it + // + Status = Dir->Open ( + Dir, + &NewDir, + FileContext->FileName, + EFI_FILE_READ_ONLY, + 0 + ); + if (!FileContext->IsRoot) { + Dir->Close (Dir); + } + + if (EFI_ERROR (Status)) { + return Status; + } + + DirInfo = FileInfo (NewDir); + if (DirInfo == NULL) { + return EFI_NOT_FOUND; + } + + if ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0) { + return EFI_INVALID_PARAMETER; + } + + FileContext->DevicePath = FileDevicePath ( + FileContext->Handle, + FileContext->FileName + ); + + DirBufferSize = sizeof (EFI_FILE_INFO) + 1024; + DirInfo = AllocateZeroPool (DirBufferSize); + if (DirInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Get all files in current directory + // Pass 1 to get Directories + // Pass 2 to get files that are EFI images + // + for (Pass = 1; Pass <= 2; Pass++) { + NewDir->SetPosition (NewDir, 0); + for (;;) { + BufferSize = DirBufferSize; + Status = NewDir->Read (NewDir, &BufferSize, DirInfo); + if (EFI_ERROR (Status) || BufferSize == 0) { + break; + } + + if (((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 && Pass == 2) || + ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0 && Pass == 1) + ) { + // + // Pass 1 is for Directories + // Pass 2 is for file names + // + continue; + } + + NewMenuEntry = CreateMenuEntry (); + if (NULL == NewMenuEntry) { + return EFI_OUT_OF_RESOURCES; + } + + NewFileContext = (SECUREBOOT_FILE_CONTEXT *) NewMenuEntry->FileContext; + NewFileContext->Handle = FileContext->Handle; + NewFileContext->FileName = AppendFileName ( + FileContext->FileName, + DirInfo->FileName + ); + NewFileContext->FHandle = NewDir; + NewFileContext->DevicePath = FileDevicePath ( + NewFileContext->Handle, + NewFileContext->FileName + ); + NewMenuEntry->HelpString = NULL; + + NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY); + if (NewFileContext->IsDir) { + BufferSize = StrLen (DirInfo->FileName) * 2 + 6; + NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize); + + UnicodeSPrint ( + NewMenuEntry->DisplayString, + BufferSize, + L"<%s>", + DirInfo->FileName + ); + + } else { + NewMenuEntry->DisplayString = StrDuplicate (DirInfo->FileName); + } + + NewFileContext->IsRoot = FALSE; + NewFileContext->IsLoadFile = FALSE; + NewFileContext->IsRemovableMedia = FALSE; + + NewMenuEntry->OptionNumber = OptionNumber; + OptionNumber++; + InsertTailList (&DirectoryMenu.Head, &NewMenuEntry->Link); + } + } + + DirectoryMenu.MenuNumber = OptionNumber; + FreePool (DirInfo); + return EFI_SUCCESS; +} + +/** + Refresh the global UpdateData structure. + +**/ +VOID +RefreshUpdateData ( + VOID + ) +{ + // + // Free current updated date + // + if (mStartOpCodeHandle != NULL) { + HiiFreeOpCodeHandle (mStartOpCodeHandle); + } + + // + // Create new OpCode Handle + // + mStartOpCodeHandle = HiiAllocateOpCodeHandle (); + + // + // Create Hii Extend Label OpCode as the start opcode + // + mStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + mStartOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + mStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; +} + +/** + Update the File Explore page. + + @param[in] HiiHandle Hii Handle of the package to be updated. + @param[in] MenuOption The Menu whose string tokens need to be updated. + @param[in] FeCurrentState Current file explorer state. + +**/ +VOID +UpdateFileExplorePage ( + IN EFI_HII_HANDLE HiiHandle, + IN SECUREBOOT_MENU_OPTION *MenuOption, + IN FILE_EXPLORER_STATE FeCurrentState + ) +{ + UINTN Index; + SECUREBOOT_MENU_ENTRY *NewMenuEntry; + SECUREBOOT_FILE_CONTEXT *NewFileContext; + EFI_FORM_ID FormId; + EFI_FORM_ID FileFormId; + + if (FeCurrentState == FileExplorerStateEnrollPkFile) { + FormId = SECUREBOOT_ADD_PK_FILE_FORM_ID; + FileFormId = FORM_FILE_EXPLORER_ID_PK; + } else if (FeCurrentState == FileExplorerStateEnrollKekFile) { + FormId = FORMID_ENROLL_KEK_FORM; + FileFormId = FORM_FILE_EXPLORER_ID_KEK; + } else if (FeCurrentState == FileExplorerStateEnrollSignatureFileToDb) { + FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DB; + FileFormId = FORM_FILE_EXPLORER_ID_DB; + } else if (FeCurrentState == FileExplorerStateEnrollSignatureFileToDbx) { + FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBX; + FileFormId = FORM_FILE_EXPLORER_ID_DBX; + } else { + return; + } + + NewMenuEntry = NULL; + NewFileContext = NULL; + + RefreshUpdateData (); + mStartLabel->Number = FORM_FILE_EXPLORER_ID; + + for (Index = 0; Index < MenuOption->MenuNumber; Index++) { + NewMenuEntry = GetMenuEntry (MenuOption, Index); + NewFileContext = (SECUREBOOT_FILE_CONTEXT *) NewMenuEntry->FileContext; + + if (NewFileContext->IsDir) { + // + // Create Text opcode for directory. + // + HiiCreateActionOpCode ( + mStartOpCodeHandle, + (UINT16) (FILE_OPTION_OFFSET + Index), + NewMenuEntry->DisplayStringToken, + STRING_TOKEN (STR_NULL), + EFI_IFR_FLAG_CALLBACK, + 0 + ); + } else { + + // + // Create Goto opcode for file. + // + HiiCreateGotoOpCode ( + mStartOpCodeHandle, + FormId, + NewMenuEntry->DisplayStringToken, + STRING_TOKEN (STR_NULL), + EFI_IFR_FLAG_CALLBACK, + (UINT16) (FILE_OPTION_OFFSET + Index) + ); + } + } + + HiiUpdateForm ( + HiiHandle, + &gSecureBootConfigFormSetGuid, + FileFormId, + mStartOpCodeHandle, // Label FORM_FILE_EXPLORER_ID + mEndOpCodeHandle // LABEL_END + ); +} + +/** + Update the file explorer page with the refreshed file system. + + @param[in] PrivateData Module private data. + @param[in] KeyValue Key value to identify the type of data to expect. + + @retval TRUE Inform the caller to create a callback packet to exit file explorer. + @retval FALSE Indicate that there is no need to exit file explorer. + +**/ +BOOLEAN +UpdateFileExplorer ( + IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData, + IN UINT16 KeyValue + ) +{ + UINT16 FileOptionMask; + SECUREBOOT_MENU_ENTRY *NewMenuEntry; + SECUREBOOT_FILE_CONTEXT *NewFileContext; + EFI_FORM_ID FormId; + BOOLEAN ExitFileExplorer; + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath; + + NewMenuEntry = NULL; + NewFileContext = NULL; + ExitFileExplorer = FALSE; + FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue); + + if (PrivateData->FeDisplayContext == FileExplorerDisplayUnknown) { + // + // First in, display file system. + // + FreeMenu (&FsOptionMenu); + FindFileSystem (); + + CreateMenuStringToken (PrivateData->HiiHandle, &FsOptionMenu); + UpdateFileExplorePage (PrivateData->HiiHandle, &FsOptionMenu, PrivateData->FeCurrentState); + + PrivateData->FeDisplayContext = FileExplorerDisplayFileSystem; + } else { + if (PrivateData->FeDisplayContext == FileExplorerDisplayFileSystem) { + NewMenuEntry = GetMenuEntry (&FsOptionMenu, FileOptionMask); + } else if (PrivateData->FeDisplayContext == FileExplorerDisplayDirectory) { + NewMenuEntry = GetMenuEntry (&DirectoryMenu, FileOptionMask); + } + + NewFileContext = (SECUREBOOT_FILE_CONTEXT *) NewMenuEntry->FileContext; + + if (NewFileContext->IsDir ) { + PrivateData->FeDisplayContext = FileExplorerDisplayDirectory; + + RemoveEntryList (&NewMenuEntry->Link); + FreeMenu (&DirectoryMenu); + Status = FindFiles (NewMenuEntry); + if (EFI_ERROR (Status)) { + ExitFileExplorer = TRUE; + goto OnExit; + } + CreateMenuStringToken (PrivateData->HiiHandle, &DirectoryMenu); + DestroyMenuEntry (NewMenuEntry); + + UpdateFileExplorePage (PrivateData->HiiHandle, &DirectoryMenu, PrivateData->FeCurrentState); + + } else { + if (PrivateData->FeCurrentState == FileExplorerStateEnrollPkFile) { + FormId = SECUREBOOT_ADD_PK_FILE_FORM_ID; + } else if (PrivateData->FeCurrentState == FileExplorerStateEnrollKekFile) { + FormId = FORMID_ENROLL_KEK_FORM; + } else if (PrivateData->FeCurrentState == FileExplorerStateEnrollSignatureFileToDb) { + FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DB; + } else if (PrivateData->FeCurrentState == FileExplorerStateEnrollSignatureFileToDbx) { + FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBX; + } else { + return FALSE; + } + + PrivateData->MenuEntry = NewMenuEntry; + PrivateData->FileContext->FileName = NewFileContext->FileName; + + TmpDevicePath = NewFileContext->DevicePath; + OpenFileByDevicePath ( + &TmpDevicePath, + &PrivateData->FileContext->FHandle, + EFI_FILE_MODE_READ, + 0 + ); + + // + // Create Subtitle op-code for the display string of the option. + // + RefreshUpdateData (); + mStartLabel->Number = FormId; + + HiiCreateSubTitleOpCode ( + mStartOpCodeHandle, + NewMenuEntry->DisplayStringToken, + 0, + 0, + 0 + ); + + HiiUpdateForm ( + PrivateData->HiiHandle, + &gSecureBootConfigFormSetGuid, + FormId, + mStartOpCodeHandle, // Label FormId + mEndOpCodeHandle // LABEL_END + ); + } + } + +OnExit: + return ExitFileExplorer; +} + +/** + Clean up the dynamic opcode at label and form specified by both LabelId. + + @param[in] LabelId It is both the Form ID and Label ID for opcode deletion. + @param[in] PrivateData Module private data. + +**/ +VOID +CleanUpPage ( + IN UINT16 LabelId, + IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData + ) +{ + RefreshUpdateData (); + + // + // Remove all op-codes from dynamic page + // + mStartLabel->Number = LabelId; + HiiUpdateForm ( + PrivateData->HiiHandle, + &gSecureBootConfigFormSetGuid, + LabelId, + mStartOpCodeHandle, // Label LabelId + mEndOpCodeHandle // LABEL_END + ); +} + diff --git a/OvmfPkg/SecureBootConfigDxe/SecureBootConfigImpl.c b/OvmfPkg/SecureBootConfigDxe/SecureBootConfigImpl.c new file mode 100644 index 0000000000..c82c0f4f95 --- /dev/null +++ b/OvmfPkg/SecureBootConfigDxe/SecureBootConfigImpl.c @@ -0,0 +1,2804 @@ +/** @file + HII Config Access protocol implementation of SecureBoot configuration module. + +Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "SecureBootConfigImpl.h" + +CHAR16 mSecureBootStorageName[] = L"SECUREBOOT_CONFIGURATION"; + +SECUREBOOT_CONFIG_PRIVATE_DATA mSecureBootConfigPrivateDateTemplate = { + SECUREBOOT_CONFIG_PRIVATE_DATA_SIGNATURE, + { + SecureBootExtractConfig, + SecureBootRouteConfig, + SecureBootCallback + } +}; + +HII_VENDOR_DEVICE_PATH mSecureBootHiiVendorDevicePath = { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) + } + }, + SECUREBOOT_CONFIG_FORM_SET_GUID + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + (UINT8) (END_DEVICE_PATH_LENGTH), + (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) + } + } +}; + + +// +// OID ASN.1 Value for Hash Algorithms +// +UINT8 mHashOidValue[] = { + 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, // OBJ_md5 + 0x2B, 0x0E, 0x03, 0x02, 0x1A, // OBJ_sha1 + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, // OBJ_sha224 + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, // OBJ_sha256 + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, // OBJ_sha384 + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, // OBJ_sha512 + }; + +HASH_TABLE mHash[] = { + { L"SHA1", 20, &mHashOidValue[8], 5, Sha1GetContextSize, Sha1Init, Sha1Update, Sha1Final }, + { L"SHA224", 28, &mHashOidValue[13], 9, NULL, NULL, NULL, NULL }, + { L"SHA256", 32, &mHashOidValue[22], 9, Sha256GetContextSize,Sha256Init, Sha256Update, Sha256Final}, + { L"SHA384", 48, &mHashOidValue[31], 9, NULL, NULL, NULL, NULL }, + { L"SHA512", 64, &mHashOidValue[40], 9, NULL, NULL, NULL, NULL } +}; + +// +// Variable Definitions +// +UINT32 mPeCoffHeaderOffset = 0; +WIN_CERTIFICATE *mCertificate = NULL; +IMAGE_TYPE mImageType; +UINT8 *mImageBase = NULL; +UINTN mImageSize = 0; +UINT8 mImageDigest[MAX_DIGEST_SIZE]; +UINTN mImageDigestSize; +EFI_GUID mCertType; +EFI_IMAGE_SECURITY_DATA_DIRECTORY *mSecDataDir = NULL; +EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader; + +// +// Possible DER-encoded certificate file suffixes, end with NULL pointer. +// +CHAR16* mDerEncodedSuffix[] = { + L".cer", + L".der", + L".crt", + NULL +}; +CHAR16* mSupportX509Suffix = L"*.cer/der/crt"; + +/** + This code checks if the FileSuffix is one of the possible DER-encoded certificate suffix. + + @param[in] FileSuffix The suffix of the input certificate file + + @retval TRUE It's a DER-encoded certificate. + @retval FALSE It's NOT a DER-encoded certificate. + +**/ +BOOLEAN +IsDerEncodeCertificate ( + IN CONST CHAR16 *FileSuffix +) +{ + UINTN Index; + for (Index = 0; mDerEncodedSuffix[Index] != NULL; Index++) { + if (StrCmp (FileSuffix, mDerEncodedSuffix[Index]) == 0) { + return TRUE; + } + } + return FALSE; +} + +/** + Set Secure Boot option into variable space. + + @param[in] VarValue The option of Secure Boot. + + @retval EFI_SUCCESS The operation is finished successfully. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +SaveSecureBootVariable ( + IN UINT8 VarValue + ) +{ + EFI_STATUS Status; + + Status = gRT->SetVariable ( + EFI_SECURE_BOOT_ENABLE_NAME, + &gEfiSecureBootEnableDisableGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof (UINT8), + &VarValue + ); + return Status; +} + +/** + Create a time based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION_2 + descriptor with the input data. NO authentication is required in this function. + + @param[in, out] DataSize On input, the size of Data buffer in bytes. + On output, the size of data returned in Data + buffer in bytes. + @param[in, out] Data On input, Pointer to data buffer to be wrapped or + pointer to NULL to wrap an empty payload. + On output, Pointer to the new payload date buffer allocated from pool, + it's caller's responsibility to free the memory when finish using it. + + @retval EFI_SUCCESS Create time based payload successfully. + @retval EFI_OUT_OF_RESOURCES There are not enough memory resourses to create time based payload. + @retval EFI_INVALID_PARAMETER The parameter is invalid. + @retval Others Unexpected error happens. + +**/ +EFI_STATUS +CreateTimeBasedPayload ( + IN OUT UINTN *DataSize, + IN OUT UINT8 **Data + ) +{ + EFI_STATUS Status; + UINT8 *NewData; + UINT8 *Payload; + UINTN PayloadSize; + EFI_VARIABLE_AUTHENTICATION_2 *DescriptorData; + UINTN DescriptorSize; + EFI_TIME Time; + + if (Data == NULL || DataSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // In Setup mode or Custom mode, the variable does not need to be signed but the + // parameters to the SetVariable() call still need to be prepared as authenticated + // variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate + // data in it. + // + Payload = *Data; + PayloadSize = *DataSize; + + DescriptorSize = OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData); + NewData = (UINT8*) AllocateZeroPool (DescriptorSize + PayloadSize); + if (NewData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if ((Payload != NULL) && (PayloadSize != 0)) { + CopyMem (NewData + DescriptorSize, Payload, PayloadSize); + } + + DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData); + + ZeroMem (&Time, sizeof (EFI_TIME)); + Status = gRT->GetTime (&Time, NULL); + if (EFI_ERROR (Status)) { + FreePool(NewData); + return Status; + } + Time.Pad1 = 0; + Time.Nanosecond = 0; + Time.TimeZone = 0; + Time.Daylight = 0; + Time.Pad2 = 0; + CopyMem (&DescriptorData->TimeStamp, &Time, sizeof (EFI_TIME)); + + DescriptorData->AuthInfo.Hdr.dwLength = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData); + DescriptorData->AuthInfo.Hdr.wRevision = 0x0200; + DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID; + CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertPkcs7Guid); + + if (Payload != NULL) { + FreePool(Payload); + } + + *DataSize = DescriptorSize + PayloadSize; + *Data = NewData; + return EFI_SUCCESS; +} + +/** + Internal helper function to delete a Variable given its name and GUID, NO authentication + required. + + @param[in] VariableName Name of the Variable. + @param[in] VendorGuid GUID of the Variable. + + @retval EFI_SUCCESS Variable deleted successfully. + @retval Others The driver failed to start the device. + +**/ +EFI_STATUS +DeleteVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid + ) +{ + EFI_STATUS Status; + VOID* Variable; + UINT8 *Data; + UINTN DataSize; + UINT32 Attr; + + GetVariable2 (VariableName, VendorGuid, &Variable, NULL); + if (Variable == NULL) { + return EFI_SUCCESS; + } + + Data = NULL; + DataSize = 0; + Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS + | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; + + Status = CreateTimeBasedPayload (&DataSize, &Data); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status)); + return Status; + } + + Status = gRT->SetVariable ( + VariableName, + VendorGuid, + Attr, + DataSize, + Data + ); + if (Data != NULL) { + FreePool (Data); + } + return Status; +} + +/** + Generate the PK signature list from the X509 Certificate storing file (.cer) + + @param[in] X509File FileHandle of X509 Certificate storing file. + @param[out] PkCert Point to the data buffer to store the signature list. + + @return EFI_UNSUPPORTED Unsupported Key Length. + @return EFI_OUT_OF_RESOURCES There are not enough memory resourses to form the signature list. + +**/ +EFI_STATUS +CreatePkX509SignatureList ( + IN EFI_FILE_HANDLE X509File, + OUT EFI_SIGNATURE_LIST **PkCert + ) +{ + EFI_STATUS Status; + UINT8 *X509Data; + UINTN X509DataSize; + EFI_SIGNATURE_DATA *PkCertData; + + X509Data = NULL; + PkCertData = NULL; + X509DataSize = 0; + + Status = ReadFileContent (X509File, (VOID**) &X509Data, &X509DataSize, 0); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + ASSERT (X509Data != NULL); + + // + // Allocate space for PK certificate list and initialize it. + // Create PK database entry with SignatureHeaderSize equals 0. + // + *PkCert = (EFI_SIGNATURE_LIST*) AllocateZeroPool ( + sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1 + + X509DataSize + ); + if (*PkCert == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + (*PkCert)->SignatureListSize = (UINT32) (sizeof(EFI_SIGNATURE_LIST) + + sizeof(EFI_SIGNATURE_DATA) - 1 + + X509DataSize); + (*PkCert)->SignatureSize = (UINT32) (sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize); + (*PkCert)->SignatureHeaderSize = 0; + CopyGuid (&(*PkCert)->SignatureType, &gEfiCertX509Guid); + PkCertData = (EFI_SIGNATURE_DATA*) ((UINTN)(*PkCert) + + sizeof(EFI_SIGNATURE_LIST) + + (*PkCert)->SignatureHeaderSize); + CopyGuid (&PkCertData->SignatureOwner, &gEfiGlobalVariableGuid); + // + // Fill the PK database with PKpub data from X509 certificate file. + // + CopyMem (&(PkCertData->SignatureData[0]), X509Data, X509DataSize); + +ON_EXIT: + + if (X509Data != NULL) { + FreePool (X509Data); + } + + if (EFI_ERROR(Status) && *PkCert != NULL) { + FreePool (*PkCert); + *PkCert = NULL; + } + + return Status; +} + +/** + Enroll new PK into the System without original PK's authentication. + + The SignatureOwner GUID will be the same with PK's vendorguid. + + @param[in] PrivateData The module's private data. + + @retval EFI_SUCCESS New PK enrolled successfully. + @retval EFI_INVALID_PARAMETER The parameter is invalid. + @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources. + +**/ +EFI_STATUS +EnrollPlatformKey ( + IN SECUREBOOT_CONFIG_PRIVATE_DATA* Private + ) +{ + EFI_STATUS Status; + UINT32 Attr; + UINTN DataSize; + EFI_SIGNATURE_LIST *PkCert; + UINT16* FilePostFix; + + if (Private->FileContext->FileName == NULL) { + return EFI_INVALID_PARAMETER; + } + + PkCert = NULL; + + // + // Parse the file's postfix. Only support DER encoded X.509 certificate files. + // + FilePostFix = Private->FileContext->FileName + StrLen (Private->FileContext->FileName) - 4; + if (!IsDerEncodeCertificate(FilePostFix)) { + DEBUG ((EFI_D_ERROR, "Unsupported file type, only DER encoded certificate (%s) is supported.", mSupportX509Suffix)); + return EFI_INVALID_PARAMETER; + } + DEBUG ((EFI_D_INFO, "FileName= %s\n", Private->FileContext->FileName)); + DEBUG ((EFI_D_INFO, "FilePostFix = %s\n", FilePostFix)); + + // + // Prase the selected PK file and generature PK certificate list. + // + Status = CreatePkX509SignatureList ( + Private->FileContext->FHandle, + &PkCert + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + ASSERT (PkCert != NULL); + + // + // Set Platform Key variable. + // + Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS + | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; + DataSize = PkCert->SignatureListSize; + Status = CreateTimeBasedPayload (&DataSize, (UINT8**) &PkCert); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status)); + goto ON_EXIT; + } + + Status = gRT->SetVariable( + EFI_PLATFORM_KEY_NAME, + &gEfiGlobalVariableGuid, + Attr, + DataSize, + PkCert + ); + if (EFI_ERROR (Status)) { + if (Status == EFI_OUT_OF_RESOURCES) { + DEBUG ((EFI_D_ERROR, "Enroll PK failed with out of resource.\n")); + } + goto ON_EXIT; + } + +ON_EXIT: + + if (PkCert != NULL) { + FreePool(PkCert); + } + + if (Private->FileContext->FHandle != NULL) { + CloseFile (Private->FileContext->FHandle); + Private->FileContext->FHandle = NULL; + } + + return Status; +} + +/** + Remove the PK variable. + + @retval EFI_SUCCESS Delete PK successfully. + @retval Others Could not allow to delete PK. + +**/ +EFI_STATUS +DeletePlatformKey ( + VOID +) +{ + EFI_STATUS Status; + + Status = DeleteVariable ( + EFI_PLATFORM_KEY_NAME, + &gEfiGlobalVariableGuid + ); + return Status; +} + +/** + Enroll a new KEK item from public key storing file (*.pbk). + + @param[in] PrivateData The module's private data. + + @retval EFI_SUCCESS New KEK enrolled successfully. + @retval EFI_INVALID_PARAMETER The parameter is invalid. + @retval EFI_UNSUPPORTED Unsupported command. + @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources. + +**/ +EFI_STATUS +EnrollRsa2048ToKek ( + IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + UINT32 Attr; + UINTN DataSize; + EFI_SIGNATURE_LIST *KekSigList; + UINTN KeyBlobSize; + UINT8 *KeyBlob; + CPL_KEY_INFO *KeyInfo; + EFI_SIGNATURE_DATA *KEKSigData; + UINTN KekSigListSize; + UINT8 *KeyBuffer; + UINTN KeyLenInBytes; + + Attr = 0; + DataSize = 0; + KeyBuffer = NULL; + KeyBlobSize = 0; + KeyBlob = NULL; + KeyInfo = NULL; + KEKSigData = NULL; + KekSigList = NULL; + KekSigListSize = 0; + + // + // Form the KeKpub certificate list into EFI_SIGNATURE_LIST type. + // First, We have to parse out public key data from the pbk key file. + // + Status = ReadFileContent ( + Private->FileContext->FHandle, + (VOID**) &KeyBlob, + &KeyBlobSize, + 0 + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + ASSERT (KeyBlob != NULL); + KeyInfo = (CPL_KEY_INFO *) KeyBlob; + if (KeyInfo->KeyLengthInBits / 8 != WIN_CERT_UEFI_RSA2048_SIZE) { + DEBUG ((DEBUG_ERROR, "Unsupported key length, Only RSA2048 is supported.\n")); + Status = EFI_UNSUPPORTED; + goto ON_EXIT; + } + + // + // Convert the Public key to fix octet string format represented in RSA PKCS#1. + // + KeyLenInBytes = KeyInfo->KeyLengthInBits / 8; + KeyBuffer = AllocateZeroPool (KeyLenInBytes); + if (KeyBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + Int2OctStr ( + (UINTN*) (KeyBlob + sizeof (CPL_KEY_INFO)), + KeyLenInBytes / sizeof (UINTN), + KeyBuffer, + KeyLenInBytes + ); + CopyMem(KeyBlob + sizeof(CPL_KEY_INFO), KeyBuffer, KeyLenInBytes); + + // + // Form an new EFI_SIGNATURE_LIST. + // + KekSigListSize = sizeof(EFI_SIGNATURE_LIST) + + sizeof(EFI_SIGNATURE_DATA) - 1 + + WIN_CERT_UEFI_RSA2048_SIZE; + + KekSigList = (EFI_SIGNATURE_LIST*) AllocateZeroPool (KekSigListSize); + if (KekSigList == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + KekSigList->SignatureListSize = sizeof(EFI_SIGNATURE_LIST) + + sizeof(EFI_SIGNATURE_DATA) - 1 + + WIN_CERT_UEFI_RSA2048_SIZE; + KekSigList->SignatureHeaderSize = 0; + KekSigList->SignatureSize = sizeof(EFI_SIGNATURE_DATA) - 1 + WIN_CERT_UEFI_RSA2048_SIZE; + CopyGuid (&KekSigList->SignatureType, &gEfiCertRsa2048Guid); + + KEKSigData = (EFI_SIGNATURE_DATA*)((UINT8*)KekSigList + sizeof(EFI_SIGNATURE_LIST)); + CopyGuid (&KEKSigData->SignatureOwner, Private->SignatureGUID); + CopyMem ( + KEKSigData->SignatureData, + KeyBlob + sizeof(CPL_KEY_INFO), + WIN_CERT_UEFI_RSA2048_SIZE + ); + + // + // Check if KEK entry has been already existed. + // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the + // new KEK to original variable. + // + Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS + | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; + Status = CreateTimeBasedPayload (&KekSigListSize, (UINT8**) &KekSigList); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status)); + goto ON_EXIT; + } + + Status = gRT->GetVariable( + EFI_KEY_EXCHANGE_KEY_NAME, + &gEfiGlobalVariableGuid, + NULL, + &DataSize, + NULL + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + Attr |= EFI_VARIABLE_APPEND_WRITE; + } else if (Status != EFI_NOT_FOUND) { + goto ON_EXIT; + } + + // + // Done. Now we have formed the correct KEKpub database item, just set it into variable storage, + // + Status = gRT->SetVariable( + EFI_KEY_EXCHANGE_KEY_NAME, + &gEfiGlobalVariableGuid, + Attr, + KekSigListSize, + KekSigList + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + +ON_EXIT: + + CloseFile (Private->FileContext->FHandle); + Private->FileContext->FHandle = NULL; + Private->FileContext->FileName = NULL; + + if (Private->SignatureGUID != NULL) { + FreePool (Private->SignatureGUID); + Private->SignatureGUID = NULL; + } + + if (KeyBlob != NULL) { + FreePool (KeyBlob); + } + if (KeyBuffer != NULL) { + FreePool (KeyBuffer); + } + if (KekSigList != NULL) { + FreePool (KekSigList); + } + + return Status; +} + +/** + Enroll a new KEK item from X509 certificate file. + + @param[in] PrivateData The module's private data. + + @retval EFI_SUCCESS New X509 is enrolled successfully. + @retval EFI_INVALID_PARAMETER The parameter is invalid. + @retval EFI_UNSUPPORTED Unsupported command. + @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources. + +**/ +EFI_STATUS +EnrollX509ToKek ( + IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + UINTN X509DataSize; + VOID *X509Data; + EFI_SIGNATURE_DATA *KEKSigData; + EFI_SIGNATURE_LIST *KekSigList; + UINTN DataSize; + UINTN KekSigListSize; + UINT32 Attr; + + X509Data = NULL; + X509DataSize = 0; + KekSigList = NULL; + KekSigListSize = 0; + DataSize = 0; + KEKSigData = NULL; + + Status = ReadFileContent ( + Private->FileContext->FHandle, + &X509Data, + &X509DataSize, + 0 + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + ASSERT (X509Data != NULL); + + KekSigListSize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize; + KekSigList = (EFI_SIGNATURE_LIST*) AllocateZeroPool (KekSigListSize); + if (KekSigList == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + // + // Fill Certificate Database parameters. + // + KekSigList->SignatureListSize = (UINT32) KekSigListSize; + KekSigList->SignatureHeaderSize = 0; + KekSigList->SignatureSize = (UINT32) (sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize); + CopyGuid (&KekSigList->SignatureType, &gEfiCertX509Guid); + + KEKSigData = (EFI_SIGNATURE_DATA*) ((UINT8*) KekSigList + sizeof (EFI_SIGNATURE_LIST)); + CopyGuid (&KEKSigData->SignatureOwner, Private->SignatureGUID); + CopyMem (KEKSigData->SignatureData, X509Data, X509DataSize); + + // + // Check if KEK been already existed. + // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the + // new kek to original variable + // + Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS + | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; + Status = CreateTimeBasedPayload (&KekSigListSize, (UINT8**) &KekSigList); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status)); + goto ON_EXIT; + } + + Status = gRT->GetVariable( + EFI_KEY_EXCHANGE_KEY_NAME, + &gEfiGlobalVariableGuid, + NULL, + &DataSize, + NULL + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + Attr |= EFI_VARIABLE_APPEND_WRITE; + } else if (Status != EFI_NOT_FOUND) { + goto ON_EXIT; + } + + Status = gRT->SetVariable( + EFI_KEY_EXCHANGE_KEY_NAME, + &gEfiGlobalVariableGuid, + Attr, + KekSigListSize, + KekSigList + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + +ON_EXIT: + + CloseFile (Private->FileContext->FHandle); + Private->FileContext->FileName = NULL; + Private->FileContext->FHandle = NULL; + + if (Private->SignatureGUID != NULL) { + FreePool (Private->SignatureGUID); + Private->SignatureGUID = NULL; + } + + if (KekSigList != NULL) { + FreePool (KekSigList); + } + + return Status; +} + +/** + Enroll new KEK into the System without PK's authentication. + The SignatureOwner GUID will be Private->SignatureGUID. + + @param[in] PrivateData The module's private data. + + @retval EFI_SUCCESS New KEK enrolled successful. + @retval EFI_INVALID_PARAMETER The parameter is invalid. + @retval others Fail to enroll KEK data. + +**/ +EFI_STATUS +EnrollKeyExchangeKey ( + IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private + ) +{ + UINT16* FilePostFix; + + if ((Private->FileContext->FileName == NULL) || (Private->SignatureGUID == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Parse the file's postfix. Supports DER-encoded X509 certificate, + // and .pbk as RSA public key file. + // + FilePostFix = Private->FileContext->FileName + StrLen (Private->FileContext->FileName) - 4; + if (IsDerEncodeCertificate(FilePostFix)) { + return EnrollX509ToKek (Private); + } else if (CompareMem (FilePostFix, L".pbk",4) == 0) { + return EnrollRsa2048ToKek (Private); + } else { + return EFI_INVALID_PARAMETER; + } +} + +/** + Enroll a new X509 certificate into Signature Database (DB or DBX) without + KEK's authentication. + + @param[in] PrivateData The module's private data. + @param[in] VariableName Variable name of signature database, must be + EFI_IMAGE_SECURITY_DATABASE or EFI_IMAGE_SECURITY_DATABASE1. + + @retval EFI_SUCCESS New X509 is enrolled successfully. + @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources. + +**/ +EFI_STATUS +EnrollX509toSigDB ( + IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private, + IN CHAR16 *VariableName + ) +{ + EFI_STATUS Status; + UINTN X509DataSize; + VOID *X509Data; + EFI_SIGNATURE_LIST *SigDBCert; + EFI_SIGNATURE_DATA *SigDBCertData; + VOID *Data; + UINTN DataSize; + UINTN SigDBSize; + UINT32 Attr; + + X509DataSize = 0; + SigDBSize = 0; + DataSize = 0; + X509Data = NULL; + SigDBCert = NULL; + SigDBCertData = NULL; + Data = NULL; + + Status = ReadFileContent ( + Private->FileContext->FHandle, + &X509Data, + &X509DataSize, + 0 + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + ASSERT (X509Data != NULL); + + SigDBSize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize; + + Data = AllocateZeroPool (SigDBSize); + if (Data == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + // + // Fill Certificate Database parameters. + // + SigDBCert = (EFI_SIGNATURE_LIST*) Data; + SigDBCert->SignatureListSize = (UINT32) SigDBSize; + SigDBCert->SignatureHeaderSize = 0; + SigDBCert->SignatureSize = (UINT32) (sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize); + CopyGuid (&SigDBCert->SignatureType, &gEfiCertX509Guid); + + SigDBCertData = (EFI_SIGNATURE_DATA*) ((UINT8* ) SigDBCert + sizeof (EFI_SIGNATURE_LIST)); + CopyGuid (&SigDBCertData->SignatureOwner, Private->SignatureGUID); + CopyMem ((UINT8* ) (SigDBCertData->SignatureData), X509Data, X509DataSize); + + // + // Check if signature database entry has been already existed. + // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the + // new signature data to original variable + // + Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS + | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; + Status = CreateTimeBasedPayload (&SigDBSize, (UINT8**) &Data); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status)); + goto ON_EXIT; + } + + Status = gRT->GetVariable( + VariableName, + &gEfiImageSecurityDatabaseGuid, + NULL, + &DataSize, + NULL + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + Attr |= EFI_VARIABLE_APPEND_WRITE; + } else if (Status != EFI_NOT_FOUND) { + goto ON_EXIT; + } + + Status = gRT->SetVariable( + VariableName, + &gEfiImageSecurityDatabaseGuid, + Attr, + SigDBSize, + Data + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + +ON_EXIT: + + CloseFile (Private->FileContext->FHandle); + Private->FileContext->FileName = NULL; + Private->FileContext->FHandle = NULL; + + if (Private->SignatureGUID != NULL) { + FreePool (Private->SignatureGUID); + Private->SignatureGUID = NULL; + } + + if (Data != NULL) { + FreePool (Data); + } + + if (X509Data != NULL) { + FreePool (X509Data); + } + + return Status; +} + +/** + Load PE/COFF image information into internal buffer and check its validity. + + @retval EFI_SUCCESS Successful + @retval EFI_UNSUPPORTED Invalid PE/COFF file + @retval EFI_ABORTED Serious error occurs, like file I/O error etc. + +**/ +EFI_STATUS +LoadPeImage ( + VOID + ) +{ + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_IMAGE_NT_HEADERS32 *NtHeader32; + EFI_IMAGE_NT_HEADERS64 *NtHeader64; + + NtHeader32 = NULL; + NtHeader64 = NULL; + // + // Read the Dos header + // + DosHdr = (EFI_IMAGE_DOS_HEADER*)(mImageBase); + if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) + { + // + // DOS image header is present, + // So read the PE header after the DOS image header + // + mPeCoffHeaderOffset = DosHdr->e_lfanew; + } + else + { + mPeCoffHeaderOffset = 0; + } + + // + // Read PE header and check the signature validity and machine compatibility + // + NtHeader32 = (EFI_IMAGE_NT_HEADERS32*) (mImageBase + mPeCoffHeaderOffset); + if (NtHeader32->Signature != EFI_IMAGE_NT_SIGNATURE) + { + return EFI_UNSUPPORTED; + } + + mNtHeader.Pe32 = NtHeader32; + + // + // Check the architecture field of PE header and get the Certificate Data Directory data + // Note the size of FileHeader field is constant for both IA32 and X64 arch + // + if ((NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) + || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_EBC)) { + // + // IA-32 Architecture + // + mImageType = ImageType_IA32; + mSecDataDir = (EFI_IMAGE_SECURITY_DATA_DIRECTORY*) &(NtHeader32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]); + } + else if ((NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64) + || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_X64)) { + // + // 64-bits Architecture + // + mImageType = ImageType_X64; + NtHeader64 = (EFI_IMAGE_NT_HEADERS64 *) (mImageBase + mPeCoffHeaderOffset); + mSecDataDir = (EFI_IMAGE_SECURITY_DATA_DIRECTORY*) &(NtHeader64->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]); + } else { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +/** + Calculate hash of Pe/Coff image based on the authenticode image hashing in + PE/COFF Specification 8.0 Appendix A + + @param[in] HashAlg Hash algorithm type. + + @retval TRUE Successfully hash image. + @retval FALSE Fail in hash image. + +**/ +BOOLEAN +HashPeImage ( + IN UINT32 HashAlg + ) +{ + BOOLEAN Status; + UINT16 Magic; + EFI_IMAGE_SECTION_HEADER *Section; + VOID *HashCtx; + UINTN CtxSize; + UINT8 *HashBase; + UINTN HashSize; + UINTN SumOfBytesHashed; + EFI_IMAGE_SECTION_HEADER *SectionHeader; + UINTN Index; + UINTN Pos; + + HashCtx = NULL; + SectionHeader = NULL; + Status = FALSE; + + if ((HashAlg != HASHALG_SHA1) && (HashAlg != HASHALG_SHA256)) { + return FALSE; + } + + // + // Initialize context of hash. + // + ZeroMem (mImageDigest, MAX_DIGEST_SIZE); + + if (HashAlg == HASHALG_SHA1) { + mImageDigestSize = SHA1_DIGEST_SIZE; + mCertType = gEfiCertSha1Guid; + } else if (HashAlg == HASHALG_SHA256) { + mImageDigestSize = SHA256_DIGEST_SIZE; + mCertType = gEfiCertSha256Guid; + } + + CtxSize = mHash[HashAlg].GetContextSize(); + + HashCtx = AllocatePool (CtxSize); + ASSERT (HashCtx != NULL); + + // 1. Load the image header into memory. + + // 2. Initialize a SHA hash context. + Status = mHash[HashAlg].HashInit(HashCtx); + if (!Status) { + goto Done; + } + // + // Measuring PE/COFF Image Header; + // But CheckSum field and SECURITY data directory (certificate) are excluded + // + if (mNtHeader.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value + // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the + // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC + // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC + // + Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC; + } else { + // + // Get the magic value from the PE/COFF Optional Header + // + Magic = mNtHeader.Pe32->OptionalHeader.Magic; + } + + // + // 3. Calculate the distance from the base of the image header to the image checksum address. + // 4. Hash the image header from its base to beginning of the image checksum. + // + HashBase = mImageBase; + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset. + // + HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.CheckSum) - HashBase); + } else { + // + // Use PE32+ offset. + // + HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - HashBase); + } + + Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize); + if (!Status) { + goto Done; + } + // + // 5. Skip over the image checksum (it occupies a single ULONG). + // 6. Get the address of the beginning of the Cert Directory. + // 7. Hash everything from the end of the checksum to the start of the Cert Directory. + // + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset. + // + HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase); + } else { + // + // Use PE32+ offset. + // + HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase); + } + + Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize); + if (!Status) { + goto Done; + } + // + // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.) + // 9. Hash everything from the end of the Cert Directory to the end of image header. + // + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset + // + HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; + HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - mImageBase); + } else { + // + // Use PE32+ offset. + // + HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; + HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - mImageBase); + } + + Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize); + if (!Status) { + goto Done; + } + // + // 10. Set the SUM_OF_BYTES_HASHED to the size of the header. + // + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset. + // + SumOfBytesHashed = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders; + } else { + // + // Use PE32+ offset + // + SumOfBytesHashed = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders; + } + + // + // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER + // structures in the image. The 'NumberOfSections' field of the image + // header indicates how big the table should be. Do not include any + // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero. + // + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * mNtHeader.Pe32->FileHeader.NumberOfSections); + ASSERT (SectionHeader != NULL); + // + // 12. Using the 'PointerToRawData' in the referenced section headers as + // a key, arrange the elements in the table in ascending order. In other + // words, sort the section headers according to the disk-file offset of + // the section. + // + Section = (EFI_IMAGE_SECTION_HEADER *) ( + mImageBase + + mPeCoffHeaderOffset + + sizeof (UINT32) + + sizeof (EFI_IMAGE_FILE_HEADER) + + mNtHeader.Pe32->FileHeader.SizeOfOptionalHeader + ); + for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) { + Pos = Index; + while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) { + CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER)); + Pos--; + } + CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER)); + Section += 1; + } + + // + // 13. Walk through the sorted table, bring the corresponding section + // into memory, and hash the entire section (using the 'SizeOfRawData' + // field in the section header to determine the amount of data to hash). + // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED . + // 15. Repeat steps 13 and 14 for all the sections in the sorted table. + // + for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) { + Section = &SectionHeader[Index]; + if (Section->SizeOfRawData == 0) { + continue; + } + HashBase = mImageBase + Section->PointerToRawData; + HashSize = (UINTN) Section->SizeOfRawData; + + Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize); + if (!Status) { + goto Done; + } + + SumOfBytesHashed += HashSize; + } + + // + // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra + // data in the file that needs to be added to the hash. This data begins + // at file offset SUM_OF_BYTES_HASHED and its length is: + // FileSize - (CertDirectory->Size) + // + if (mImageSize > SumOfBytesHashed) { + HashBase = mImageBase + SumOfBytesHashed; + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset. + // + HashSize = (UINTN)( + mImageSize - + mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - + SumOfBytesHashed); + } else { + // + // Use PE32+ offset. + // + HashSize = (UINTN)( + mImageSize - + mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - + SumOfBytesHashed); + } + + Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize); + if (!Status) { + goto Done; + } + } + + Status = mHash[HashAlg].HashFinal(HashCtx, mImageDigest); + +Done: + if (HashCtx != NULL) { + FreePool (HashCtx); + } + if (SectionHeader != NULL) { + FreePool (SectionHeader); + } + return Status; +} + +/** + Recognize the Hash algorithm in PE/COFF Authenticode and caculate hash of + Pe/Coff image based on the authenticated image hashing in PE/COFF Specification + 8.0 Appendix A + + @retval EFI_UNSUPPORTED Hash algorithm is not supported. + @retval EFI_SUCCESS Hash successfully. + +**/ +EFI_STATUS +HashPeImageByType ( + VOID + ) +{ + UINT8 Index; + WIN_CERTIFICATE_EFI_PKCS *PkcsCertData; + + PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->Offset); + + for (Index = 0; Index < HASHALG_MAX; Index++) { + // + // Check the Hash algorithm in PE/COFF Authenticode. + // According to PKCS#7 Definition: + // SignedData ::= SEQUENCE { + // version Version, + // digestAlgorithms DigestAlgorithmIdentifiers, + // contentInfo ContentInfo, + // .... } + // The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing + // This field has the fixed offset (+32) in final Authenticode ASN.1 data. + // Fixed offset (+32) is calculated based on two bytes of length encoding. + // + if ((*(PkcsCertData->CertData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) { + // + // Only support two bytes of Long Form of Length Encoding. + // + continue; + } + + // + if (CompareMem (PkcsCertData->CertData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) { + break; + } + } + + if (Index == HASHALG_MAX) { + return EFI_UNSUPPORTED; + } + + // + // HASH PE Image based on Hash algorithm in PE/COFF Authenticode. + // + if (!HashPeImage(Index)) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +/** + Enroll a new executable's signature into Signature Database. + + @param[in] PrivateData The module's private data. + @param[in] VariableName Variable name of signature database, must be + EFI_IMAGE_SECURITY_DATABASE or EFI_IMAGE_SECURITY_DATABASE1. + + @retval EFI_SUCCESS New signature is enrolled successfully. + @retval EFI_INVALID_PARAMETER The parameter is invalid. + @retval EFI_UNSUPPORTED Unsupported command. + @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources. + +**/ +EFI_STATUS +EnrollImageSignatureToSigDB ( + IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private, + IN CHAR16 *VariableName + ) +{ + EFI_STATUS Status; + EFI_SIGNATURE_LIST *SigDBCert; + EFI_SIGNATURE_DATA *SigDBCertData; + VOID *Data; + UINTN DataSize; + UINTN SigDBSize; + UINT32 Attr; + WIN_CERTIFICATE_UEFI_GUID *GuidCertData; + + Data = NULL; + GuidCertData = NULL; + + // + // Form the SigDB certificate list. + // Format the data item into EFI_SIGNATURE_LIST type. + // + // We need to parse executable's signature data from specified signed executable file. + // In current implementation, we simply trust the pass-in signed executable file. + // In reality, it's OS's responsibility to verify the signed executable file. + // + + // + // Read the whole file content + // + Status = ReadFileContent( + Private->FileContext->FHandle, + (VOID **) &mImageBase, + &mImageSize, + 0 + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + ASSERT (mImageBase != NULL); + + Status = LoadPeImage (); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + if (mSecDataDir->SizeOfCert == 0) { + if (!HashPeImage (HASHALG_SHA256)) { + Status = EFI_SECURITY_VIOLATION; + goto ON_EXIT; + } + } else { + + // + // Read the certificate data + // + mCertificate = (WIN_CERTIFICATE *)(mImageBase + mSecDataDir->Offset); + + if (mCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) { + GuidCertData = (WIN_CERTIFICATE_UEFI_GUID*) mCertificate; + if (CompareMem (&GuidCertData->CertType, &gEfiCertTypeRsa2048Sha256Guid, sizeof(EFI_GUID)) != 0) { + Status = EFI_ABORTED; + goto ON_EXIT; + } + + if (!HashPeImage (HASHALG_SHA256)) { + Status = EFI_ABORTED; + goto ON_EXIT;; + } + + } else if (mCertificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) { + + Status = HashPeImageByType (); + if (EFI_ERROR (Status)) { + goto ON_EXIT;; + } + } else { + Status = EFI_ABORTED; + goto ON_EXIT; + } + } + + // + // Create a new SigDB entry. + // + SigDBSize = sizeof(EFI_SIGNATURE_LIST) + + sizeof(EFI_SIGNATURE_DATA) - 1 + + (UINT32) mImageDigestSize; + + Data = (UINT8*) AllocateZeroPool (SigDBSize); + if (Data == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + // + // Adjust the Certificate Database parameters. + // + SigDBCert = (EFI_SIGNATURE_LIST*) Data; + SigDBCert->SignatureListSize = (UINT32) SigDBSize; + SigDBCert->SignatureHeaderSize = 0; + SigDBCert->SignatureSize = sizeof(EFI_SIGNATURE_DATA) - 1 + (UINT32) mImageDigestSize; + CopyGuid (&SigDBCert->SignatureType, &mCertType); + + SigDBCertData = (EFI_SIGNATURE_DATA*)((UINT8*)SigDBCert + sizeof(EFI_SIGNATURE_LIST)); + CopyGuid (&SigDBCertData->SignatureOwner, Private->SignatureGUID); + CopyMem (SigDBCertData->SignatureData, mImageDigest, mImageDigestSize); + + Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS + | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; + Status = CreateTimeBasedPayload (&SigDBSize, (UINT8**) &Data); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status)); + goto ON_EXIT; + } + + // + // Check if SigDB variable has been already existed. + // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the + // new signature data to original variable + // + DataSize = 0; + Status = gRT->GetVariable( + VariableName, + &gEfiImageSecurityDatabaseGuid, + NULL, + &DataSize, + NULL + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + Attr |= EFI_VARIABLE_APPEND_WRITE; + } else if (Status != EFI_NOT_FOUND) { + goto ON_EXIT; + } + + // + // Enroll the variable. + // + Status = gRT->SetVariable( + VariableName, + &gEfiImageSecurityDatabaseGuid, + Attr, + SigDBSize, + Data + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + +ON_EXIT: + + CloseFile (Private->FileContext->FHandle); + Private->FileContext->FHandle = NULL; + Private->FileContext->FileName = NULL; + + if (Private->SignatureGUID != NULL) { + FreePool (Private->SignatureGUID); + Private->SignatureGUID = NULL; + } + + if (Data != NULL) { + FreePool (Data); + } + + if (mImageBase != NULL) { + FreePool (mImageBase); + mImageBase = NULL; + } + + return Status; +} + +/** + Enroll signature into DB/DBX without KEK's authentication. + The SignatureOwner GUID will be Private->SignatureGUID. + + @param[in] PrivateData The module's private data. + @param[in] VariableName Variable name of signature database, must be + EFI_IMAGE_SECURITY_DATABASE or EFI_IMAGE_SECURITY_DATABASE1. + + @retval EFI_SUCCESS New signature enrolled successfully. + @retval EFI_INVALID_PARAMETER The parameter is invalid. + @retval others Fail to enroll signature data. + +**/ +EFI_STATUS +EnrollSignatureDatabase ( + IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private, + IN CHAR16 *VariableName + ) +{ + UINT16* FilePostFix; + + if ((Private->FileContext->FileName == NULL) || (Private->FileContext->FHandle == NULL) || (Private->SignatureGUID == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Parse the file's postfix. + // + FilePostFix = Private->FileContext->FileName + StrLen (Private->FileContext->FileName) - 4; + if (IsDerEncodeCertificate(FilePostFix)) { + // + // Supports DER-encoded X509 certificate. + // + return EnrollX509toSigDB (Private, VariableName); + } + + return EnrollImageSignatureToSigDB (Private, VariableName); +} + +/** + List all signatures in specified signature database (e.g. KEK/DB/DBX) + by GUID in the page for user to select and delete as needed. + + @param[in] PrivateData Module's private data. + @param[in] VariableName The variable name of the vendor's signature database. + @param[in] VendorGuid A unique identifier for the vendor. + @param[in] LabelNumber Label number to insert opcodes. + @param[in] FormId Form ID of current page. + @param[in] QuestionIdBase Base question id of the signature list. + + @retval EFI_SUCCESS Success to update the signature list page + @retval EFI_OUT_OF_RESOURCES Unable to allocate required resources. + +**/ +EFI_STATUS +UpdateDeletePage ( + IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData, + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT16 LabelNumber, + IN EFI_FORM_ID FormId, + IN EFI_QUESTION_ID QuestionIdBase + ) +{ + EFI_STATUS Status; + UINT32 Index; + UINTN CertCount; + UINTN GuidIndex; + VOID *StartOpCodeHandle; + VOID *EndOpCodeHandle; + EFI_IFR_GUID_LABEL *StartLabel; + EFI_IFR_GUID_LABEL *EndLabel; + UINTN DataSize; + UINT8 *Data; + EFI_SIGNATURE_LIST *CertList; + EFI_SIGNATURE_DATA *Cert; + UINT32 ItemDataSize; + CHAR16 *GuidStr; + EFI_STRING_ID GuidID; + EFI_STRING_ID Help; + + Data = NULL; + CertList = NULL; + Cert = NULL; + GuidStr = NULL; + StartOpCodeHandle = NULL; + EndOpCodeHandle = NULL; + + // + // Initialize the container for dynamic opcodes. + // + StartOpCodeHandle = HiiAllocateOpCodeHandle (); + if (StartOpCodeHandle == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + EndOpCodeHandle = HiiAllocateOpCodeHandle (); + if (EndOpCodeHandle == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + // + // Create Hii Extend Label OpCode. + // + StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + StartOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + StartLabel->Number = LabelNumber; + + EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + EndOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + EndLabel->Number = LABEL_END; + + // + // Read Variable. + // + DataSize = 0; + Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, Data); + if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) { + goto ON_EXIT; + } + + Data = (UINT8 *) AllocateZeroPool (DataSize); + if (Data == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, Data); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + GuidStr = AllocateZeroPool (100); + if (GuidStr == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + // + // Enumerate all KEK pub data. + // + ItemDataSize = (UINT32) DataSize; + CertList = (EFI_SIGNATURE_LIST *) Data; + GuidIndex = 0; + + while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) { + + if (CompareGuid (&CertList->SignatureType, &gEfiCertRsa2048Guid)) { + Help = STRING_TOKEN (STR_CERT_TYPE_RSA2048_SHA256_GUID); + } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) { + Help = STRING_TOKEN (STR_CERT_TYPE_PCKS7_GUID); + } else if (CompareGuid (&CertList->SignatureType, &gEfiCertSha1Guid)) { + Help = STRING_TOKEN (STR_CERT_TYPE_SHA1_GUID); + } else if (CompareGuid (&CertList->SignatureType, &gEfiCertSha256Guid)) { + Help = STRING_TOKEN (STR_CERT_TYPE_SHA256_GUID); + } else { + // + // The signature type is not supported in current implementation. + // + continue; + } + + CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize; + for (Index = 0; Index < CertCount; Index++) { + Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + + sizeof (EFI_SIGNATURE_LIST) + + CertList->SignatureHeaderSize + + Index * CertList->SignatureSize); + // + // Display GUID and help + // + GuidToString (&Cert->SignatureOwner, GuidStr, 100); + GuidID = HiiSetString (PrivateData->HiiHandle, 0, GuidStr, NULL); + HiiCreateCheckBoxOpCode ( + StartOpCodeHandle, + (EFI_QUESTION_ID) (QuestionIdBase + GuidIndex++), + 0, + 0, + GuidID, + Help, + EFI_IFR_FLAG_CALLBACK, + 0, + NULL + ); + } + + ItemDataSize -= CertList->SignatureListSize; + CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); + } + +ON_EXIT: + HiiUpdateForm ( + PrivateData->HiiHandle, + &gSecureBootConfigFormSetGuid, + FormId, + StartOpCodeHandle, + EndOpCodeHandle + ); + + if (StartOpCodeHandle != NULL) { + HiiFreeOpCodeHandle (StartOpCodeHandle); + } + + if (EndOpCodeHandle != NULL) { + HiiFreeOpCodeHandle (EndOpCodeHandle); + } + + if (Data != NULL) { + FreePool (Data); + } + + if (GuidStr != NULL) { + FreePool (GuidStr); + } + + return EFI_SUCCESS; +} + +/** + Delete a KEK entry from KEK database. + + @param[in] PrivateData Module's private data. + @param[in] QuestionId Question id of the KEK item to delete. + + @retval EFI_SUCCESS Delete kek item successfully. + @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources. + +**/ +EFI_STATUS +DeleteKeyExchangeKey ( + IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData, + IN EFI_QUESTION_ID QuestionId + ) +{ + EFI_STATUS Status; + UINTN DataSize; + UINT8 *Data; + UINT8 *OldData; + UINT32 Attr; + UINT32 Index; + EFI_SIGNATURE_LIST *CertList; + EFI_SIGNATURE_LIST *NewCertList; + EFI_SIGNATURE_DATA *Cert; + UINTN CertCount; + UINT32 Offset; + BOOLEAN IsKEKItemFound; + UINT32 KekDataSize; + UINTN DeleteKekIndex; + UINTN GuidIndex; + + Data = NULL; + OldData = NULL; + CertList = NULL; + Cert = NULL; + Attr = 0; + DeleteKekIndex = QuestionId - OPTION_DEL_KEK_QUESTION_ID; + + // + // Get original KEK variable. + // + DataSize = 0; + Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &DataSize, NULL); + if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) { + goto ON_EXIT; + } + + OldData = (UINT8*)AllocateZeroPool(DataSize); + if (OldData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, &Attr, &DataSize, OldData); + if (EFI_ERROR(Status)) { + goto ON_EXIT; + } + + // + // Allocate space for new variable. + // + Data = (UINT8*) AllocateZeroPool (DataSize); + if (Data == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + // + // Enumerate all KEK pub data and erasing the target item. + // + IsKEKItemFound = FALSE; + KekDataSize = (UINT32) DataSize; + CertList = (EFI_SIGNATURE_LIST *) OldData; + Offset = 0; + GuidIndex = 0; + while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) { + if (CompareGuid (&CertList->SignatureType, &gEfiCertRsa2048Guid) || + CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) { + CopyMem (Data + Offset, CertList, (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize)); + NewCertList = (EFI_SIGNATURE_LIST *)(Data + Offset); + Offset += (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); + Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); + CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize; + for (Index = 0; Index < CertCount; Index++) { + if (GuidIndex == DeleteKekIndex ) { + // + // Find it! Skip it! + // + NewCertList->SignatureListSize -= CertList->SignatureSize; + IsKEKItemFound = TRUE; + } else { + // + // This item doesn't match. Copy it to the Data buffer. + // + CopyMem (Data + Offset, Cert, CertList->SignatureSize); + Offset += CertList->SignatureSize; + } + GuidIndex++; + Cert = (EFI_SIGNATURE_DATA *) ((UINT8*) Cert + CertList->SignatureSize); + } + } else { + // + // This List doesn't match. Copy it to the Data buffer. + // + CopyMem (Data + Offset, CertList, CertList->SignatureListSize); + Offset += CertList->SignatureListSize; + } + + KekDataSize -= CertList->SignatureListSize; + CertList = (EFI_SIGNATURE_LIST*) ((UINT8*) CertList + CertList->SignatureListSize); + } + + if (!IsKEKItemFound) { + // + // Doesn't find the Kek Item! + // + Status = EFI_NOT_FOUND; + goto ON_EXIT; + } + + // + // Delete the Signature header if there is no signature in the list. + // + KekDataSize = Offset; + CertList = (EFI_SIGNATURE_LIST*) Data; + Offset = 0; + ZeroMem (OldData, KekDataSize); + while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) { + CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize; + DEBUG ((DEBUG_ERROR, " CertCount = %x\n", CertCount)); + if (CertCount != 0) { + CopyMem (OldData + Offset, CertList, CertList->SignatureListSize); + Offset += CertList->SignatureListSize; + } + KekDataSize -= CertList->SignatureListSize; + CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); + } + + DataSize = Offset; + if ((Attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) { + Status = CreateTimeBasedPayload (&DataSize, &OldData); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status)); + goto ON_EXIT; + } + } + + Status = gRT->SetVariable( + EFI_KEY_EXCHANGE_KEY_NAME, + &gEfiGlobalVariableGuid, + Attr, + DataSize, + OldData + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to set variable, Status = %r\n", Status)); + goto ON_EXIT; + } + +ON_EXIT: + if (Data != NULL) { + FreePool(Data); + } + + if (OldData != NULL) { + FreePool(OldData); + } + + return UpdateDeletePage ( + PrivateData, + EFI_KEY_EXCHANGE_KEY_NAME, + &gEfiGlobalVariableGuid, + LABEL_KEK_DELETE, + FORMID_DELETE_KEK_FORM, + OPTION_DEL_KEK_QUESTION_ID + ); +} + +/** + Delete a signature entry from siganture database. + + @param[in] PrivateData Module's private data. + @param[in] VariableName The variable name of the vendor's signature database. + @param[in] VendorGuid A unique identifier for the vendor. + @param[in] LabelNumber Label number to insert opcodes. + @param[in] FormId Form ID of current page. + @param[in] QuestionIdBase Base question id of the signature list. + @param[in] DeleteIndex Signature index to delete. + + @retval EFI_SUCCESS Delete siganture successfully. + @retval EFI_NOT_FOUND Can't find the signature item, + @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources. +**/ +EFI_STATUS +DeleteSignature ( + IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData, + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT16 LabelNumber, + IN EFI_FORM_ID FormId, + IN EFI_QUESTION_ID QuestionIdBase, + IN UINTN DeleteIndex + ) +{ + EFI_STATUS Status; + UINTN DataSize; + UINT8 *Data; + UINT8 *OldData; + UINT32 Attr; + UINT32 Index; + EFI_SIGNATURE_LIST *CertList; + EFI_SIGNATURE_LIST *NewCertList; + EFI_SIGNATURE_DATA *Cert; + UINTN CertCount; + UINT32 Offset; + BOOLEAN IsItemFound; + UINT32 ItemDataSize; + UINTN GuidIndex; + + Data = NULL; + OldData = NULL; + CertList = NULL; + Cert = NULL; + Attr = 0; + + // + // Get original signature list data. + // + DataSize = 0; + Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, NULL); + if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) { + goto ON_EXIT; + } + + OldData = (UINT8 *) AllocateZeroPool (DataSize); + if (OldData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + Status = gRT->GetVariable (VariableName, VendorGuid, &Attr, &DataSize, OldData); + if (EFI_ERROR(Status)) { + goto ON_EXIT; + } + + // + // Allocate space for new variable. + // + Data = (UINT8*) AllocateZeroPool (DataSize); + if (Data == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + // + // Enumerate all signature data and erasing the target item. + // + IsItemFound = FALSE; + ItemDataSize = (UINT32) DataSize; + CertList = (EFI_SIGNATURE_LIST *) OldData; + Offset = 0; + GuidIndex = 0; + while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) { + if (CompareGuid (&CertList->SignatureType, &gEfiCertRsa2048Guid) || + CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid) || + CompareGuid (&CertList->SignatureType, &gEfiCertSha1Guid) || + CompareGuid (&CertList->SignatureType, &gEfiCertSha256Guid) + ) { + // + // Copy EFI_SIGNATURE_LIST header then calculate the signature count in this list. + // + CopyMem (Data + Offset, CertList, (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize)); + NewCertList = (EFI_SIGNATURE_LIST*) (Data + Offset); + Offset += (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); + Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); + CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize; + for (Index = 0; Index < CertCount; Index++) { + if (GuidIndex == DeleteIndex) { + // + // Find it! Skip it! + // + NewCertList->SignatureListSize -= CertList->SignatureSize; + IsItemFound = TRUE; + } else { + // + // This item doesn't match. Copy it to the Data buffer. + // + CopyMem (Data + Offset, (UINT8*)(Cert), CertList->SignatureSize); + Offset += CertList->SignatureSize; + } + GuidIndex++; + Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize); + } + } else { + // + // This List doesn't match. Just copy it to the Data buffer. + // + CopyMem (Data + Offset, (UINT8*)(CertList), CertList->SignatureListSize); + Offset += CertList->SignatureListSize; + } + + ItemDataSize -= CertList->SignatureListSize; + CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); + } + + if (!IsItemFound) { + // + // Doesn't find the signature Item! + // + Status = EFI_NOT_FOUND; + goto ON_EXIT; + } + + // + // Delete the EFI_SIGNATURE_LIST header if there is no signature in the list. + // + ItemDataSize = Offset; + CertList = (EFI_SIGNATURE_LIST *) Data; + Offset = 0; + ZeroMem (OldData, ItemDataSize); + while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) { + CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize; + DEBUG ((DEBUG_ERROR, " CertCount = %x\n", CertCount)); + if (CertCount != 0) { + CopyMem (OldData + Offset, (UINT8*)(CertList), CertList->SignatureListSize); + Offset += CertList->SignatureListSize; + } + ItemDataSize -= CertList->SignatureListSize; + CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); + } + + DataSize = Offset; + if ((Attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) { + Status = CreateTimeBasedPayload (&DataSize, &OldData); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status)); + goto ON_EXIT; + } + } + + Status = gRT->SetVariable( + VariableName, + VendorGuid, + Attr, + DataSize, + OldData + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to set variable, Status = %r\n", Status)); + goto ON_EXIT; + } + +ON_EXIT: + if (Data != NULL) { + FreePool(Data); + } + + if (OldData != NULL) { + FreePool(OldData); + } + + return UpdateDeletePage ( + PrivateData, + VariableName, + VendorGuid, + LabelNumber, + FormId, + QuestionIdBase + ); +} + +/** + This function extracts configuration from variable. + + @param[in, out] ConfigData Point to SecureBoot configuration private data. + +**/ +VOID +SecureBootExtractConfigFromVariable ( + IN OUT SECUREBOOT_CONFIGURATION *ConfigData + ) +{ + UINT8 *SecureBootEnable; + UINT8 *SetupMode; + UINT8 *SecureBoot; + UINT8 *SecureBootMode; + + SecureBootEnable = NULL; + SetupMode = NULL; + SecureBoot = NULL; + SecureBootMode = NULL; + + // + // If the SecureBootEnable Variable doesn't exist, hide the SecureBoot Enable/Disable + // Checkbox. + // + GetVariable2 (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID**)&SecureBootEnable, NULL); + if (SecureBootEnable == NULL) { + ConfigData->HideSecureBoot = TRUE; + } else { + ConfigData->HideSecureBoot = FALSE; + } + + // + // If it is Physical Presence User, set the PhysicalPresent to true. + // + if (UserPhysicalPresent()) { + ConfigData->PhysicalPresent = TRUE; + } else { + ConfigData->PhysicalPresent = FALSE; + } + + // + // If there is no PK then the Delete Pk button will be gray. + // + GetVariable2 (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&SetupMode, NULL); + if (SetupMode == NULL || (*SetupMode) == SETUP_MODE) { + ConfigData->HasPk = FALSE; + } else { + ConfigData->HasPk = TRUE; + } + + // + // If the value of SecureBoot variable is 1, the platform is operating in secure boot mode. + // + GetVariable2 (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&SecureBoot, NULL); + if (SecureBoot != NULL && *SecureBoot == SECURE_BOOT_MODE_ENABLE) { + ConfigData->SecureBootState = TRUE; + } else { + ConfigData->SecureBootState = FALSE; + } + + // + // Get the SecureBootMode from CustomMode variable. + // + GetVariable2 (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, (VOID**)&SecureBootMode, NULL); + if (SecureBootMode == NULL) { + ConfigData->SecureBootMode = STANDARD_SECURE_BOOT_MODE; + } else { + ConfigData->SecureBootMode = *(SecureBootMode); + } + +} + +/** + This function allows a caller to extract the current configuration for one + or more named elements from the target driver. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Request A null-terminated Unicode string in + format. + @param[out] Progress On return, points to a character in the Request + string. Points to the string's null terminator if + request was successful. Points to the most recent + '&' before the first failing name/value pair (or + the beginning of the string if the failure is in + the first name/value pair) if the request was not + successful. + @param[out] Results A null-terminated Unicode string in + format which has all values filled + in for the names in the Request string. String to + be allocated by the called function. + + @retval EFI_SUCCESS The Results is filled with the requested values. + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results. + @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this + driver. + +**/ +EFI_STATUS +EFIAPI +SecureBootExtractConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Request, + OUT EFI_STRING *Progress, + OUT EFI_STRING *Results + ) +{ + EFI_STATUS Status; + UINTN BufferSize; + UINTN Size; + SECUREBOOT_CONFIGURATION Configuration; + EFI_STRING ConfigRequest; + EFI_STRING ConfigRequestHdr; + SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData; + BOOLEAN AllocatedRequest; + + if (Progress == NULL || Results == NULL) { + return EFI_INVALID_PARAMETER; + } + + AllocatedRequest = FALSE; + ConfigRequestHdr = NULL; + ConfigRequest = NULL; + Size = 0; + + ZeroMem (&Configuration, sizeof (Configuration)); + PrivateData = SECUREBOOT_CONFIG_PRIVATE_FROM_THIS (This); + *Progress = Request; + + if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &gSecureBootConfigFormSetGuid, mSecureBootStorageName)) { + return EFI_NOT_FOUND; + } + + // + // Get Configuration from Variable. + // + SecureBootExtractConfigFromVariable (&Configuration); + + BufferSize = sizeof (SECUREBOOT_CONFIGURATION); + ConfigRequest = Request; + if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) { + // + // Request is set to NULL or OFFSET is NULL, construct full request string. + // + // Allocate and fill a buffer large enough to hold the template + // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator + // + ConfigRequestHdr = HiiConstructConfigHdr (&gSecureBootConfigFormSetGuid, mSecureBootStorageName, PrivateData->DriverHandle); + Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16); + ConfigRequest = AllocateZeroPool (Size); + ASSERT (ConfigRequest != NULL); + AllocatedRequest = TRUE; + UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize); + FreePool (ConfigRequestHdr); + ConfigRequestHdr = NULL; + } + + Status = gHiiConfigRouting->BlockToConfig ( + gHiiConfigRouting, + ConfigRequest, + (UINT8 *) &Configuration, + BufferSize, + Results, + Progress + ); + + // + // Free the allocated config request string. + // + if (AllocatedRequest) { + FreePool (ConfigRequest); + } + + // + // Set Progress string to the original request string. + // + if (Request == NULL) { + *Progress = NULL; + } else if (StrStr (Request, L"OFFSET") == NULL) { + *Progress = Request + StrLen (Request); + } + + return Status; +} + +/** + This function processes the results of changes in configuration. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Configuration A null-terminated Unicode string in + format. + @param[out] Progress A pointer to a string filled in with the offset of + the most recent '&' before the first failing + name/value pair (or the beginning of the string if + the failure is in the first name/value pair) or + the terminating NULL if all was successful. + + @retval EFI_SUCCESS The Results is processed successfully. + @retval EFI_INVALID_PARAMETER Configuration is NULL. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this + driver. + +**/ +EFI_STATUS +EFIAPI +SecureBootRouteConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Configuration, + OUT EFI_STRING *Progress + ) +{ + if (Configuration == NULL || Progress == NULL) { + return EFI_INVALID_PARAMETER; + } + + *Progress = Configuration; + if (!HiiIsConfigHdrMatch (Configuration, &gSecureBootConfigFormSetGuid, mSecureBootStorageName)) { + return EFI_NOT_FOUND; + } + + *Progress = Configuration + StrLen (Configuration); + return EFI_SUCCESS; +} + +/** + This function is called to provide results data to the driver. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Action Specifies the type of action taken by the browser. + @param[in] QuestionId A unique value which is sent to the original + exporting driver so that it can identify the type + of data to expect. + @param[in] Type The type of value for the question. + @param[in] Value A pointer to the data being sent to the original + exporting driver. + @param[out] ActionRequest On return, points to the action requested by the + callback function. + + @retval EFI_SUCCESS The callback successfully handled the action. + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the + variable and its data. + @retval EFI_DEVICE_ERROR The variable could not be saved. + @retval EFI_UNSUPPORTED The specified Action is not supported by the + callback. + +**/ +EFI_STATUS +EFIAPI +SecureBootCallback ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN EFI_BROWSER_ACTION Action, + IN EFI_QUESTION_ID QuestionId, + IN UINT8 Type, + IN EFI_IFR_TYPE_VALUE *Value, + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest + ) +{ + EFI_INPUT_KEY Key; + EFI_STATUS Status; + SECUREBOOT_CONFIG_PRIVATE_DATA *Private; + UINTN BufferSize; + SECUREBOOT_CONFIGURATION *IfrNvData; + UINT16 LabelId; + UINT8 *SecureBootEnable; + CHAR16 PromptString[100]; + + SecureBootEnable = NULL; + + if ((This == NULL) || (Value == NULL) || (ActionRequest == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((Action != EFI_BROWSER_ACTION_CHANGED) && (Action != EFI_BROWSER_ACTION_CHANGING)) { + return EFI_UNSUPPORTED; + } + + Private = SECUREBOOT_CONFIG_PRIVATE_FROM_THIS (This); + + // + // Retrieve uncommitted data from Browser + // + BufferSize = sizeof (SECUREBOOT_CONFIGURATION); + IfrNvData = AllocateZeroPool (BufferSize); + if (IfrNvData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = EFI_SUCCESS; + + HiiGetBrowserData (NULL, NULL, BufferSize, (UINT8 *) IfrNvData); + + if (Action == EFI_BROWSER_ACTION_CHANGING) { + + switch (QuestionId) { + case KEY_SECURE_BOOT_ENABLE: + GetVariable2 (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID**)&SecureBootEnable, NULL); + if (NULL != SecureBootEnable) { + if (EFI_ERROR (SaveSecureBootVariable (Value->u8))) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Only Physical Presence User could disable secure boot!", + NULL + ); + Status = EFI_UNSUPPORTED; + } + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY; + } + break; + + case KEY_SECURE_BOOT_OPTION: + FreeMenu (&DirectoryMenu); + FreeMenu (&FsOptionMenu); + break; + + case KEY_SECURE_BOOT_KEK_OPTION: + case KEY_SECURE_BOOT_DB_OPTION: + case KEY_SECURE_BOOT_DBX_OPTION: + // + // Clear Signature GUID. + // + ZeroMem (IfrNvData->SignatureGuid, sizeof (IfrNvData->SignatureGuid)); + if (Private->SignatureGUID == NULL) { + Private->SignatureGUID = (EFI_GUID *) AllocateZeroPool (sizeof (EFI_GUID)); + if (Private->SignatureGUID == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + if (QuestionId == KEY_SECURE_BOOT_DB_OPTION) { + LabelId = SECUREBOOT_ENROLL_SIGNATURE_TO_DB; + } else if (QuestionId == KEY_SECURE_BOOT_DBX_OPTION) { + LabelId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBX; + } else { + LabelId = FORMID_ENROLL_KEK_FORM; + } + + // + // Refresh selected file. + // + CleanUpPage (LabelId, Private); + break; + + case SECUREBOOT_ADD_PK_FILE_FORM_ID: + case FORMID_ENROLL_KEK_FORM: + case SECUREBOOT_ENROLL_SIGNATURE_TO_DB: + case SECUREBOOT_ENROLL_SIGNATURE_TO_DBX: + if (QuestionId == SECUREBOOT_ADD_PK_FILE_FORM_ID) { + Private->FeCurrentState = FileExplorerStateEnrollPkFile; + } else if (QuestionId == FORMID_ENROLL_KEK_FORM) { + Private->FeCurrentState = FileExplorerStateEnrollKekFile; + } else if (QuestionId == SECUREBOOT_ENROLL_SIGNATURE_TO_DB) { + Private->FeCurrentState = FileExplorerStateEnrollSignatureFileToDb; + } else { + Private->FeCurrentState = FileExplorerStateEnrollSignatureFileToDbx; + } + + Private->FeDisplayContext = FileExplorerDisplayUnknown; + CleanUpPage (FORM_FILE_EXPLORER_ID, Private); + UpdateFileExplorer (Private, 0); + break; + + case KEY_SECURE_BOOT_DELETE_PK: + if (Value->u8) { + Status = DeletePlatformKey (); + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY; + } + break; + + case KEY_DELETE_KEK: + UpdateDeletePage ( + Private, + EFI_KEY_EXCHANGE_KEY_NAME, + &gEfiGlobalVariableGuid, + LABEL_KEK_DELETE, + FORMID_DELETE_KEK_FORM, + OPTION_DEL_KEK_QUESTION_ID + ); + break; + + case SECUREBOOT_DELETE_SIGNATURE_FROM_DB: + UpdateDeletePage ( + Private, + EFI_IMAGE_SECURITY_DATABASE, + &gEfiImageSecurityDatabaseGuid, + LABEL_DB_DELETE, + SECUREBOOT_DELETE_SIGNATURE_FROM_DB, + OPTION_DEL_DB_QUESTION_ID + ); + break; + + case SECUREBOOT_DELETE_SIGNATURE_FROM_DBX: + UpdateDeletePage ( + Private, + EFI_IMAGE_SECURITY_DATABASE1, + &gEfiImageSecurityDatabaseGuid, + LABEL_DBX_DELETE, + SECUREBOOT_DELETE_SIGNATURE_FROM_DBX, + OPTION_DEL_DBX_QUESTION_ID + ); + + break; + + case KEY_VALUE_SAVE_AND_EXIT_KEK: + Status = EnrollKeyExchangeKey (Private); + break; + + case KEY_VALUE_SAVE_AND_EXIT_DB: + Status = EnrollSignatureDatabase (Private, EFI_IMAGE_SECURITY_DATABASE); + break; + + case KEY_VALUE_SAVE_AND_EXIT_DBX: + Status = EnrollSignatureDatabase (Private, EFI_IMAGE_SECURITY_DATABASE1); + break; + + default: + if (QuestionId >= FILE_OPTION_OFFSET) { + UpdateFileExplorer (Private, QuestionId); + } else if ((QuestionId >= OPTION_DEL_KEK_QUESTION_ID) && + (QuestionId < (OPTION_DEL_KEK_QUESTION_ID + OPTION_CONFIG_RANGE))) { + DeleteKeyExchangeKey (Private, QuestionId); + } else if ((QuestionId >= OPTION_DEL_DB_QUESTION_ID) && + (QuestionId < (OPTION_DEL_DB_QUESTION_ID + OPTION_CONFIG_RANGE))) { + DeleteSignature ( + Private, + EFI_IMAGE_SECURITY_DATABASE, + &gEfiImageSecurityDatabaseGuid, + LABEL_DB_DELETE, + SECUREBOOT_DELETE_SIGNATURE_FROM_DB, + OPTION_DEL_DB_QUESTION_ID, + QuestionId - OPTION_DEL_DB_QUESTION_ID + ); + } else if ((QuestionId >= OPTION_DEL_DBX_QUESTION_ID) && + (QuestionId < (OPTION_DEL_DBX_QUESTION_ID + OPTION_CONFIG_RANGE))) { + DeleteSignature ( + Private, + EFI_IMAGE_SECURITY_DATABASE1, + &gEfiImageSecurityDatabaseGuid, + LABEL_DBX_DELETE, + SECUREBOOT_DELETE_SIGNATURE_FROM_DBX, + OPTION_DEL_DBX_QUESTION_ID, + QuestionId - OPTION_DEL_DBX_QUESTION_ID + ); + } + break; + } + } else if (Action == EFI_BROWSER_ACTION_CHANGED) { + switch (QuestionId) { + case KEY_SECURE_BOOT_ENABLE: + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT; + break; + case KEY_VALUE_SAVE_AND_EXIT_PK: + Status = EnrollPlatformKey (Private); + UnicodeSPrint ( + PromptString, + sizeof (PromptString), + L"Only DER encoded certificate file (%s) is supported.", + mSupportX509Suffix + ); + if (EFI_ERROR (Status)) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"ERROR: Unsupported file type!", + PromptString, + NULL + ); + } else { + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT; + } + break; + + case KEY_VALUE_NO_SAVE_AND_EXIT_PK: + case KEY_VALUE_NO_SAVE_AND_EXIT_KEK: + case KEY_VALUE_NO_SAVE_AND_EXIT_DB: + case KEY_VALUE_NO_SAVE_AND_EXIT_DBX: + if (Private->FileContext->FHandle != NULL) { + CloseFile (Private->FileContext->FHandle); + Private->FileContext->FHandle = NULL; + Private->FileContext->FileName = NULL; + } + + if (Private->SignatureGUID != NULL) { + FreePool (Private->SignatureGUID); + Private->SignatureGUID = NULL; + } + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT; + break; + + case KEY_SECURE_BOOT_MODE: + GetVariable2 (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, (VOID**)&SecureBootEnable, NULL); + if (NULL != SecureBootEnable) { + Status = gRT->SetVariable ( + EFI_CUSTOM_MODE_NAME, + &gEfiCustomModeEnableGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof (UINT8), + &Value->u8 + ); + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY; + IfrNvData->SecureBootMode = Value->u8; + } + break; + + case KEY_SECURE_BOOT_KEK_GUID: + case KEY_SECURE_BOOT_SIGNATURE_GUID_DB: + case KEY_SECURE_BOOT_SIGNATURE_GUID_DBX: + ASSERT (Private->SignatureGUID != NULL); + Status = StringToGuid ( + IfrNvData->SignatureGuid, + StrLen (IfrNvData->SignatureGuid), + Private->SignatureGUID + ); + if (EFI_ERROR (Status)) { + break; + } + + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY; + break; + + case KEY_SECURE_BOOT_DELETE_PK: + if (Value->u8) { + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT; + } + break; + } + } + + if (!EFI_ERROR (Status)) { + BufferSize = sizeof (SECUREBOOT_CONFIGURATION); + HiiSetBrowserData (NULL, NULL, BufferSize, (UINT8*) IfrNvData, NULL); + } + FreePool (IfrNvData); + + return EFI_SUCCESS; +} + +/** + This function publish the SecureBoot configuration Form. + + @param[in, out] PrivateData Points to SecureBoot configuration private data. + + @retval EFI_SUCCESS HII Form is installed successfully. + @retval EFI_OUT_OF_RESOURCES Not enough resource for HII Form installation. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +InstallSecureBootConfigForm ( + IN OUT SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData + ) +{ + EFI_STATUS Status; + EFI_HII_HANDLE HiiHandle; + EFI_HANDLE DriverHandle; + EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; + + DriverHandle = NULL; + ConfigAccess = &PrivateData->ConfigAccess; + Status = gBS->InstallMultipleProtocolInterfaces ( + &DriverHandle, + &gEfiDevicePathProtocolGuid, + &mSecureBootHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + ConfigAccess, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + PrivateData->DriverHandle = DriverHandle; + + // + // Publish the HII package list + // + HiiHandle = HiiAddPackages ( + &gSecureBootConfigFormSetGuid, + DriverHandle, + SecureBootConfigDxeStrings, + SecureBootConfigBin, + NULL + ); + if (HiiHandle == NULL) { + gBS->UninstallMultipleProtocolInterfaces ( + DriverHandle, + &gEfiDevicePathProtocolGuid, + &mSecureBootHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + ConfigAccess, + NULL + ); + return EFI_OUT_OF_RESOURCES; + } + + PrivateData->HiiHandle = HiiHandle; + + PrivateData->FileContext = AllocateZeroPool (sizeof (SECUREBOOT_FILE_CONTEXT)); + PrivateData->MenuEntry = AllocateZeroPool (sizeof (SECUREBOOT_MENU_ENTRY)); + + if (PrivateData->FileContext == NULL || PrivateData->MenuEntry == NULL) { + UninstallSecureBootConfigForm (PrivateData); + return EFI_OUT_OF_RESOURCES; + } + + PrivateData->FeCurrentState = FileExplorerStateInActive; + PrivateData->FeDisplayContext = FileExplorerDisplayUnknown; + + InitializeListHead (&FsOptionMenu.Head); + InitializeListHead (&DirectoryMenu.Head); + + // + // Init OpCode Handle and Allocate space for creation of Buffer + // + mStartOpCodeHandle = HiiAllocateOpCodeHandle (); + if (mStartOpCodeHandle == NULL) { + UninstallSecureBootConfigForm (PrivateData); + return EFI_OUT_OF_RESOURCES; + } + + mEndOpCodeHandle = HiiAllocateOpCodeHandle (); + if (mEndOpCodeHandle == NULL) { + UninstallSecureBootConfigForm (PrivateData); + return EFI_OUT_OF_RESOURCES; + } + + // + // Create Hii Extend Label OpCode as the start opcode + // + mStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + mStartOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + mStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + + // + // Create Hii Extend Label OpCode as the end opcode + // + mEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + mEndOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + mEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + mEndLabel->Number = LABEL_END; + + return EFI_SUCCESS; +} + +/** + This function removes SecureBoot configuration Form. + + @param[in, out] PrivateData Points to SecureBoot configuration private data. + +**/ +VOID +UninstallSecureBootConfigForm ( + IN OUT SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData + ) +{ + // + // Uninstall HII package list + // + if (PrivateData->HiiHandle != NULL) { + HiiRemovePackages (PrivateData->HiiHandle); + PrivateData->HiiHandle = NULL; + } + + // + // Uninstall HII Config Access Protocol + // + if (PrivateData->DriverHandle != NULL) { + gBS->UninstallMultipleProtocolInterfaces ( + PrivateData->DriverHandle, + &gEfiDevicePathProtocolGuid, + &mSecureBootHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + &PrivateData->ConfigAccess, + NULL + ); + PrivateData->DriverHandle = NULL; + } + + if (PrivateData->SignatureGUID != NULL) { + FreePool (PrivateData->SignatureGUID); + } + + if (PrivateData->MenuEntry != NULL) { + FreePool (PrivateData->MenuEntry); + } + + if (PrivateData->FileContext != NULL) { + FreePool (PrivateData->FileContext); + } + + FreePool (PrivateData); + + FreeMenu (&DirectoryMenu); + FreeMenu (&FsOptionMenu); + + if (mStartOpCodeHandle != NULL) { + HiiFreeOpCodeHandle (mStartOpCodeHandle); + } + + if (mEndOpCodeHandle != NULL) { + HiiFreeOpCodeHandle (mEndOpCodeHandle); + } +} diff --git a/OvmfPkg/SecureBootConfigDxe/SecureBootConfigImpl.h b/OvmfPkg/SecureBootConfigDxe/SecureBootConfigImpl.h new file mode 100644 index 0000000000..5a5ac12426 --- /dev/null +++ b/OvmfPkg/SecureBootConfigDxe/SecureBootConfigImpl.h @@ -0,0 +1,614 @@ +/** @file + The header file of HII Config Access protocol implementation of SecureBoot + configuration module. + +Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __SECUREBOOT_CONFIG_IMPL_H__ +#define __SECUREBOOT_CONFIG_IMPL_H__ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "SecureBootConfigNvData.h" + +// +// Tool generated IFR binary data and String package data +// +extern UINT8 SecureBootConfigBin[]; +extern UINT8 SecureBootConfigDxeStrings[]; + +// +// Shared IFR form update data +// +extern VOID *mStartOpCodeHandle; +extern VOID *mEndOpCodeHandle; +extern EFI_IFR_GUID_LABEL *mStartLabel; +extern EFI_IFR_GUID_LABEL *mEndLabel; + +#define MAX_CHAR 480 +#define TWO_BYTE_ENCODE 0x82 + +// +// SHA-1 digest size in bytes. +// +#define SHA1_DIGEST_SIZE 20 +// +// SHA-256 digest size in bytes +// +#define SHA256_DIGEST_SIZE 32 +// +// Set max digest size as SHA256 Output (32 bytes) by far +// +#define MAX_DIGEST_SIZE SHA256_DIGEST_SIZE + +#define WIN_CERT_UEFI_RSA2048_SIZE 256 + +// +// Support hash types +// +#define HASHALG_SHA1 0x00000000 +#define HASHALG_SHA224 0x00000001 +#define HASHALG_SHA256 0x00000002 +#define HASHALG_SHA384 0x00000003 +#define HASHALG_SHA512 0x00000004 +#define HASHALG_MAX 0x00000005 + + +#define SECUREBOOT_MENU_OPTION_SIGNATURE SIGNATURE_32 ('S', 'b', 'M', 'u') +#define SECUREBOOT_MENU_ENTRY_SIGNATURE SIGNATURE_32 ('S', 'b', 'M', 'r') + +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + EFI_GUID Guid; + UINT8 VendorDefinedData[1]; +} VENDOR_DEVICE_PATH_WITH_DATA; + +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT16 NetworkProtocol; + UINT16 LoginOption; + UINT64 Lun; + UINT16 TargetPortalGroupTag; + CHAR16 TargetName[1]; +} ISCSI_DEVICE_PATH_WITH_NAME; + +typedef enum _FILE_EXPLORER_DISPLAY_CONTEXT { + FileExplorerDisplayFileSystem, + FileExplorerDisplayDirectory, + FileExplorerDisplayUnknown +} FILE_EXPLORER_DISPLAY_CONTEXT; + +typedef enum _FILE_EXPLORER_STATE { + FileExplorerStateInActive = 0, + FileExplorerStateEnrollPkFile, + FileExplorerStateEnrollKekFile, + FileExplorerStateEnrollSignatureFileToDb, + FileExplorerStateEnrollSignatureFileToDbx, + FileExplorerStateUnknown +} FILE_EXPLORER_STATE; + +typedef struct { + CHAR16 *Str; + UINTN Len; + UINTN Maxlen; +} POOL_PRINT; + +typedef +VOID +(*DEV_PATH_FUNCTION) ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ); + +typedef struct { + UINT8 Type; + UINT8 SubType; + DEV_PATH_FUNCTION Function; +} DEVICE_PATH_STRING_TABLE; + +typedef struct { + UINTN Signature; + LIST_ENTRY Head; + UINTN MenuNumber; +} SECUREBOOT_MENU_OPTION; + +extern SECUREBOOT_MENU_OPTION FsOptionMenu; +extern SECUREBOOT_MENU_OPTION DirectoryMenu; + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + UINTN OptionNumber; + UINT16 *DisplayString; + UINT16 *HelpString; + EFI_STRING_ID DisplayStringToken; + EFI_STRING_ID HelpStringToken; + VOID *FileContext; +} SECUREBOOT_MENU_ENTRY; + +typedef struct { + EFI_HANDLE Handle; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_FILE_HANDLE FHandle; + UINT16 *FileName; + EFI_FILE_SYSTEM_VOLUME_LABEL *Info; + + BOOLEAN IsRoot; + BOOLEAN IsDir; + BOOLEAN IsRemovableMedia; + BOOLEAN IsLoadFile; + BOOLEAN IsBootLegacy; +} SECUREBOOT_FILE_CONTEXT; + + +// +// We define another format of 5th directory entry: security directory +// +typedef struct { + UINT32 Offset; // Offset of certificate + UINT32 SizeOfCert; // size of certificate appended +} EFI_IMAGE_SECURITY_DATA_DIRECTORY; + +typedef enum{ + ImageType_IA32, + ImageType_X64 +} IMAGE_TYPE; + +/// +/// HII specific Vendor Device Path definition. +/// +typedef struct { + VENDOR_DEVICE_PATH VendorDevicePath; + EFI_DEVICE_PATH_PROTOCOL End; +} HII_VENDOR_DEVICE_PATH; + +typedef struct { + UINTN Signature; + + EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess; + EFI_HII_HANDLE HiiHandle; + EFI_HANDLE DriverHandle; + + FILE_EXPLORER_STATE FeCurrentState; + FILE_EXPLORER_DISPLAY_CONTEXT FeDisplayContext; + + SECUREBOOT_MENU_ENTRY *MenuEntry; + SECUREBOOT_FILE_CONTEXT *FileContext; + + EFI_GUID *SignatureGUID; +} SECUREBOOT_CONFIG_PRIVATE_DATA; + +extern SECUREBOOT_CONFIG_PRIVATE_DATA mSecureBootConfigPrivateDateTemplate; + +#define SECUREBOOT_CONFIG_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('S', 'E', 'C', 'B') +#define SECUREBOOT_CONFIG_PRIVATE_FROM_THIS(a) CR (a, SECUREBOOT_CONFIG_PRIVATE_DATA, ConfigAccess, SECUREBOOT_CONFIG_PRIVATE_DATA_SIGNATURE) + +// +// Cryptograhpic Key Information +// +#pragma pack(1) +typedef struct _CPL_KEY_INFO { + UINT32 KeyLengthInBits; // Key Length In Bits + UINT32 BlockSize; // Operation Block Size in Bytes + UINT32 CipherBlockSize; // Output Cipher Block Size in Bytes + UINT32 KeyType; // Key Type + UINT32 CipherMode; // Cipher Mode for Symmetric Algorithm + UINT32 Flags; // Additional Key Property Flags +} CPL_KEY_INFO; +#pragma pack() + + +/** + Retrieves the size, in bytes, of the context buffer required for hash operations. + + @return The size, in bytes, of the context buffer required for hash operations. + +**/ +typedef +EFI_STATUS +(EFIAPI *HASH_GET_CONTEXT_SIZE)( + VOID + ); + +/** + Initializes user-supplied memory pointed by HashContext as hash context for + subsequent use. + + If HashContext is NULL, then ASSERT(). + + @param[in, out] HashContext Pointer to Context being initialized. + + @retval TRUE HASH context initialization succeeded. + @retval FALSE HASH context initialization failed. + +**/ +typedef +BOOLEAN +(EFIAPI *HASH_INIT)( + IN OUT VOID *HashContext + ); + + +/** + Performs digest on a data buffer of the specified length. This function can + be called multiple times to compute the digest of long or discontinuous data streams. + + If HashContext is NULL, then ASSERT(). + + @param[in, out] HashContext Pointer to the MD5 context. + @param[in] Data Pointer to the buffer containing the data to be hashed. + @param[in] DataLength Length of Data buffer in bytes. + + @retval TRUE HASH data digest succeeded. + @retval FALSE Invalid HASH context. After HashFinal function has been called, the + HASH context cannot be reused. + +**/ +typedef +BOOLEAN +(EFIAPI *HASH_UPDATE)( + IN OUT VOID *HashContext, + IN CONST VOID *Data, + IN UINTN DataLength + ); + +/** + Completes hash computation and retrieves the digest value into the specified + memory. After this function has been called, the context cannot be used again. + + If HashContext is NULL, then ASSERT(). + If HashValue is NULL, then ASSERT(). + + @param[in, out] HashContext Pointer to the MD5 context + @param[out] HashValue Pointer to a buffer that receives the HASH digest + value (16 bytes). + + @retval TRUE HASH digest computation succeeded. + @retval FALSE HASH digest computation failed. + +**/ +typedef +BOOLEAN +(EFIAPI *HASH_FINAL)( + IN OUT VOID *HashContext, + OUT UINT8 *HashValue + ); + +// +// Hash Algorithm Table +// +typedef struct { + CHAR16 *Name; ///< Name for Hash Algorithm + UINTN DigestLength; ///< Digest Length + UINT8 *OidValue; ///< Hash Algorithm OID ASN.1 Value + UINTN OidLength; ///< Length of Hash OID Value + HASH_GET_CONTEXT_SIZE GetContextSize; ///< Pointer to Hash GetContentSize function + HASH_INIT HashInit; ///< Pointer to Hash Init function + HASH_UPDATE HashUpdate; ///< Pointer to Hash Update function + HASH_FINAL HashFinal; ///< Pointer to Hash Final function +} HASH_TABLE; + +typedef struct { + WIN_CERTIFICATE Hdr; + UINT8 CertData[1]; +} WIN_CERTIFICATE_EFI_PKCS; + + +/** + This function publish the SecureBoot configuration Form. + + @param[in, out] PrivateData Points to SecureBoot configuration private data. + + @retval EFI_SUCCESS HII Form is installed successfully. + @retval EFI_OUT_OF_RESOURCES Not enough resource for HII Form installation. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +InstallSecureBootConfigForm ( + IN OUT SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData + ); + + +/** + This function removes SecureBoot configuration Form. + + @param[in, out] PrivateData Points to SecureBoot configuration private data. + +**/ +VOID +UninstallSecureBootConfigForm ( + IN OUT SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData + ); + + +/** + This function allows a caller to extract the current configuration for one + or more named elements from the target driver. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Request A null-terminated Unicode string in + format. + @param[out] Progress On return, points to a character in the Request + string. Points to the string's null terminator if + request was successful. Points to the most recent + '&' before the first failing name/value pair (or + the beginning of the string if the failure is in + the first name/value pair) if the request was not + successful. + @param[out] Results A null-terminated Unicode string in + format which has all values filled + in for the names in the Request string. String to + be allocated by the called function. + + @retval EFI_SUCCESS The Results is filled with the requested values. + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results. + @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this + driver. + +**/ +EFI_STATUS +EFIAPI +SecureBootExtractConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Request, + OUT EFI_STRING *Progress, + OUT EFI_STRING *Results + ); + + +/** + This function processes the results of changes in configuration. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Configuration A null-terminated Unicode string in + format. + @param[out] Progress A pointer to a string filled in with the offset of + the most recent '&' before the first failing + name/value pair (or the beginning of the string if + the failure is in the first name/value pair) or + the terminating NULL if all was successful. + + @retval EFI_SUCCESS The Results is processed successfully. + @retval EFI_INVALID_PARAMETER Configuration is NULL. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this + driver. + +**/ +EFI_STATUS +EFIAPI +SecureBootRouteConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Configuration, + OUT EFI_STRING *Progress + ); + + +/** + This function processes the results of changes in configuration. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Action Specifies the type of action taken by the browser. + @param[in] QuestionId A unique value which is sent to the original + exporting driver so that it can identify the type + of data to expect. + @param[in] Type The type of value for the question. + @param[in] Value A pointer to the data being sent to the original + exporting driver. + @param[out] ActionRequest On return, points to the action requested by the + callback function. + + @retval EFI_SUCCESS The callback successfully handled the action. + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the + variable and its data. + @retval EFI_DEVICE_ERROR The variable could not be saved. + @retval EFI_UNSUPPORTED The specified Action is not supported by the + callback. + +**/ +EFI_STATUS +EFIAPI +SecureBootCallback ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN EFI_BROWSER_ACTION Action, + IN EFI_QUESTION_ID QuestionId, + IN UINT8 Type, + IN EFI_IFR_TYPE_VALUE *Value, + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest + ); + + +/** + This function converts an input device structure to a Unicode string. + + @param[in] DevPath A pointer to the device path structure. + + @return A new allocated Unicode string that represents the device path. + +**/ +CHAR16 * +EFIAPI +DevicePathToStr ( + IN EFI_DEVICE_PATH_PROTOCOL *DevPath + ); + + +/** + Clean up the dynamic opcode at label and form specified by both LabelId. + + @param[in] LabelId It is both the Form ID and Label ID for opcode deletion. + @param[in] PrivateData Module private data. + +**/ +VOID +CleanUpPage ( + IN UINT16 LabelId, + IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData + ); + + +/** + Update the file explorer page with the refreshed file system. + + @param[in] PrivateData Module private data. + @param[in] KeyValue Key value to identify the type of data to expect. + + @retval TRUE Inform the caller to create a callback packet to exit file explorer. + @retval FALSE Indicate that there is no need to exit file explorer. + +**/ +BOOLEAN +UpdateFileExplorer ( + IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData, + IN UINT16 KeyValue + ); + + +/** + Free resources allocated in Allocate Rountine. + + @param[in, out] MenuOption Menu to be freed + +**/ +VOID +FreeMenu ( + IN OUT SECUREBOOT_MENU_OPTION *MenuOption + ); + + +/** + Read file content into BufferPtr, the size of the allocate buffer + is *FileSize plus AddtionAllocateSize. + + @param[in] FileHandle The file to be read. + @param[in, out] BufferPtr Pointers to the pointer of allocated buffer. + @param[out] FileSize Size of input file + @param[in] AddtionAllocateSize Addtion size the buffer need to be allocated. + In case the buffer need to contain others besides the file content. + + @retval EFI_SUCCESS The file was read into the buffer. + @retval EFI_INVALID_PARAMETER A parameter was invalid. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval others Unexpected error. + +**/ +EFI_STATUS +ReadFileContent ( + IN EFI_FILE_HANDLE FileHandle, + IN OUT VOID **BufferPtr, + OUT UINTN *FileSize, + IN UINTN AddtionAllocateSize + ); + + +/** + Close an open file handle. + + @param[in] FileHandle The file handle to close. + +**/ +VOID +CloseFile ( + IN EFI_FILE_HANDLE FileHandle + ); + + +/** + Converts a nonnegative integer to an octet string of a specified length. + + @param[in] Integer Pointer to the nonnegative integer to be converted + @param[in] IntSizeInWords Length of integer buffer in words + @param[out] OctetString Converted octet string of the specified length + @param[in] OSSizeInBytes Intended length of resulting octet string in bytes + +Returns: + + @retval EFI_SUCCESS Data conversion successfully + @retval EFI_BUFFER_TOOL_SMALL Buffer is too small for output string + +**/ +EFI_STATUS +EFIAPI +Int2OctStr ( + IN CONST UINTN *Integer, + IN UINTN IntSizeInWords, + OUT UINT8 *OctetString, + IN UINTN OSSizeInBytes + ); + + +/** + Convert a String to Guid Value. + + @param[in] Str Specifies the String to be converted. + @param[in] StrLen Number of Unicode Characters of String (exclusive \0) + @param[out] Guid Return the result Guid value. + + @retval EFI_SUCCESS The operation is finished successfully. + @retval EFI_NOT_FOUND Invalid string. + +**/ +EFI_STATUS +StringToGuid ( + IN CHAR16 *Str, + IN UINTN StrLen, + OUT EFI_GUID *Guid + ); + + +/** + Worker function that prints an EFI_GUID into specified Buffer. + + @param[in] Guid Pointer to GUID to print. + @param[in] Buffer Buffer to print Guid into. + @param[in] BufferSize Size of Buffer. + + @retval Number of characters printed. + +**/ +UINTN +GuidToString ( + IN EFI_GUID *Guid, + IN CHAR16 *Buffer, + IN UINTN BufferSize + ); + +#endif diff --git a/OvmfPkg/SecureBootConfigDxe/SecureBootConfigMisc.c b/OvmfPkg/SecureBootConfigDxe/SecureBootConfigMisc.c new file mode 100644 index 0000000000..13c7c27387 --- /dev/null +++ b/OvmfPkg/SecureBootConfigDxe/SecureBootConfigMisc.c @@ -0,0 +1,334 @@ +/** @file + Helper functions for SecureBoot configuration module. + +Copyright (c) 2012, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "SecureBootConfigImpl.h" + +/** + Read file content into BufferPtr, the size of the allocate buffer + is *FileSize plus AddtionAllocateSize. + + @param[in] FileHandle The file to be read. + @param[in, out] BufferPtr Pointers to the pointer of allocated buffer. + @param[out] FileSize Size of input file + @param[in] AddtionAllocateSize Addtion size the buffer need to be allocated. + In case the buffer need to contain others besides the file content. + + @retval EFI_SUCCESS The file was read into the buffer. + @retval EFI_INVALID_PARAMETER A parameter was invalid. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval others Unexpected error. + +**/ +EFI_STATUS +ReadFileContent ( + IN EFI_FILE_HANDLE FileHandle, + IN OUT VOID **BufferPtr, + OUT UINTN *FileSize, + IN UINTN AddtionAllocateSize + ) + +{ + UINTN BufferSize; + UINT64 SourceFileSize; + VOID *Buffer; + EFI_STATUS Status; + + if ((FileHandle == NULL) || (FileSize == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Buffer = NULL; + + // + // Get the file size + // + Status = FileHandle->SetPosition (FileHandle, (UINT64) -1); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + Status = FileHandle->GetPosition (FileHandle, &SourceFileSize); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + Status = FileHandle->SetPosition (FileHandle, 0); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + BufferSize = (UINTN) SourceFileSize + AddtionAllocateSize; + Buffer = AllocateZeroPool(BufferSize); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + BufferSize = (UINTN) SourceFileSize; + *FileSize = BufferSize; + + Status = FileHandle->Read (FileHandle, &BufferSize, Buffer); + if (EFI_ERROR (Status) || BufferSize != *FileSize) { + FreePool (Buffer); + Buffer = NULL; + Status = EFI_BAD_BUFFER_SIZE; + goto ON_EXIT; + } + +ON_EXIT: + + *BufferPtr = Buffer; + return Status; +} + +/** + Close an open file handle. + + @param[in] FileHandle The file handle to close. + +**/ +VOID +CloseFile ( + IN EFI_FILE_HANDLE FileHandle + ) +{ + if (FileHandle != NULL) { + FileHandle->Close (FileHandle); + } +} + +/** + Convert a nonnegative integer to an octet string of a specified length. + + @param[in] Integer Pointer to the nonnegative integer to be converted + @param[in] IntSizeInWords Length of integer buffer in words + @param[out] OctetString Converted octet string of the specified length + @param[in] OSSizeInBytes Intended length of resulting octet string in bytes + +Returns: + + @retval EFI_SUCCESS Data conversion successfully + @retval EFI_BUFFER_TOOL_SMALL Buffer is too small for output string + +**/ +EFI_STATUS +EFIAPI +Int2OctStr ( + IN CONST UINTN *Integer, + IN UINTN IntSizeInWords, + OUT UINT8 *OctetString, + IN UINTN OSSizeInBytes + ) +{ + CONST UINT8 *Ptr1; + UINT8 *Ptr2; + + for (Ptr1 = (CONST UINT8 *)Integer, Ptr2 = OctetString + OSSizeInBytes - 1; + Ptr1 < (UINT8 *)(Integer + IntSizeInWords) && Ptr2 >= OctetString; + Ptr1++, Ptr2--) { + *Ptr2 = *Ptr1; + } + + for (; Ptr1 < (CONST UINT8 *)(Integer + IntSizeInWords) && *Ptr1 == 0; Ptr1++); + + if (Ptr1 < (CONST UINT8 *)(Integer + IntSizeInWords)) { + return EFI_BUFFER_TOO_SMALL; + } + + if (Ptr2 >= OctetString) { + ZeroMem (OctetString, Ptr2 - OctetString + 1); + } + + return EFI_SUCCESS; +} + + + +/** + Convert a String to Guid Value. + + @param[in] Str Specifies the String to be converted. + @param[in] StrLen Number of Unicode Characters of String (exclusive \0) + @param[out] Guid Return the result Guid value. + + @retval EFI_SUCCESS The operation is finished successfully. + @retval EFI_NOT_FOUND Invalid string. + +**/ +EFI_STATUS +StringToGuid ( + IN CHAR16 *Str, + IN UINTN StrLen, + OUT EFI_GUID *Guid + ) +{ + CHAR16 *PtrBuffer; + CHAR16 *PtrPosition; + UINT16 *Buffer; + UINTN Data; + UINTN Index; + UINT16 Digits[3]; + + Buffer = (CHAR16 *) AllocateZeroPool (sizeof (CHAR16) * (StrLen + 1)); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + StrCpy (Buffer, Str); + + // + // Data1 + // + PtrBuffer = Buffer; + PtrPosition = PtrBuffer; + while (*PtrBuffer != L'\0') { + if (*PtrBuffer == L'-') { + break; + } + PtrBuffer++; + } + if (*PtrBuffer == L'\0') { + FreePool (Buffer); + return EFI_NOT_FOUND; + } + + *PtrBuffer = L'\0'; + Data = StrHexToUintn (PtrPosition); + Guid->Data1 = (UINT32)Data; + + // + // Data2 + // + PtrBuffer++; + PtrPosition = PtrBuffer; + while (*PtrBuffer != L'\0') { + if (*PtrBuffer == L'-') { + break; + } + PtrBuffer++; + } + if (*PtrBuffer == L'\0') { + FreePool (Buffer); + return EFI_NOT_FOUND; + } + *PtrBuffer = L'\0'; + Data = StrHexToUintn (PtrPosition); + Guid->Data2 = (UINT16)Data; + + // + // Data3 + // + PtrBuffer++; + PtrPosition = PtrBuffer; + while (*PtrBuffer != L'\0') { + if (*PtrBuffer == L'-') { + break; + } + PtrBuffer++; + } + if (*PtrBuffer == L'\0') { + FreePool (Buffer); + return EFI_NOT_FOUND; + } + *PtrBuffer = L'\0'; + Data = StrHexToUintn (PtrPosition); + Guid->Data3 = (UINT16)Data; + + // + // Data4[0..1] + // + for ( Index = 0 ; Index < 2 ; Index++) { + PtrBuffer++; + if ((*PtrBuffer == L'\0') || ( *(PtrBuffer + 1) == L'\0')) { + FreePool (Buffer); + return EFI_NOT_FOUND; + } + Digits[0] = *PtrBuffer; + PtrBuffer++; + Digits[1] = *PtrBuffer; + Digits[2] = L'\0'; + Data = StrHexToUintn (Digits); + Guid->Data4[Index] = (UINT8)Data; + } + + // + // skip the '-' + // + PtrBuffer++; + if ((*PtrBuffer != L'-' ) || ( *PtrBuffer == L'\0')) { + return EFI_NOT_FOUND; + } + + // + // Data4[2..7] + // + for ( ; Index < 8; Index++) { + PtrBuffer++; + if ((*PtrBuffer == L'\0') || ( *(PtrBuffer + 1) == L'\0')) { + FreePool (Buffer); + return EFI_NOT_FOUND; + } + Digits[0] = *PtrBuffer; + PtrBuffer++; + Digits[1] = *PtrBuffer; + Digits[2] = L'\0'; + Data = StrHexToUintn (Digits); + Guid->Data4[Index] = (UINT8)Data; + } + + FreePool (Buffer); + + return EFI_SUCCESS; +} + +/** + Worker function that prints an EFI_GUID into specified Buffer. + + @param[in] Guid Pointer to GUID to print. + @param[in] Buffer Buffer to print Guid into. + @param[in] BufferSize Size of Buffer. + + @retval Number of characters printed. + +**/ +UINTN +GuidToString ( + IN EFI_GUID *Guid, + IN CHAR16 *Buffer, + IN UINTN BufferSize + ) +{ + UINTN Size; + + Size = UnicodeSPrint ( + Buffer, + BufferSize, + L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + (UINTN)Guid->Data1, + (UINTN)Guid->Data2, + (UINTN)Guid->Data3, + (UINTN)Guid->Data4[0], + (UINTN)Guid->Data4[1], + (UINTN)Guid->Data4[2], + (UINTN)Guid->Data4[3], + (UINTN)Guid->Data4[4], + (UINTN)Guid->Data4[5], + (UINTN)Guid->Data4[6], + (UINTN)Guid->Data4[7] + ); + + // + // SPrint will null terminate the string. The -1 skips the null + // + return Size - 1; +} diff --git a/OvmfPkg/SecureBootConfigDxe/SecureBootConfigNvData.h b/OvmfPkg/SecureBootConfigDxe/SecureBootConfigNvData.h new file mode 100644 index 0000000000..6015dd636d --- /dev/null +++ b/OvmfPkg/SecureBootConfigDxe/SecureBootConfigNvData.h @@ -0,0 +1,118 @@ +/** @file + Header file for NV data structure definition. + +Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __SECUREBOOT_CONFIG_NV_DATA_H__ +#define __SECUREBOOT_CONFIG_NV_DATA_H__ + +#include +#include + +// +// Used by VFR for form or button identification +// +#define SECUREBOOT_CONFIGURATION_VARSTORE_ID 0x0001 +#define SECUREBOOT_CONFIGURATION_FORM_ID 0x01 +#define FORMID_SECURE_BOOT_OPTION_FORM 0x02 +#define FORMID_SECURE_BOOT_PK_OPTION_FORM 0x03 +#define FORMID_SECURE_BOOT_KEK_OPTION_FORM 0x04 +#define FORMID_SECURE_BOOT_DB_OPTION_FORM 0x05 +#define FORMID_SECURE_BOOT_DBX_OPTION_FORM 0x06 +#define FORMID_ENROLL_PK_FORM 0x07 +#define SECUREBOOT_ADD_PK_FILE_FORM_ID 0x08 +#define FORMID_ENROLL_KEK_FORM 0x09 +#define FORMID_DELETE_KEK_FORM 0x0a +#define SECUREBOOT_ENROLL_SIGNATURE_TO_DB 0x0b +#define SECUREBOOT_DELETE_SIGNATURE_FROM_DB 0x0c +#define SECUREBOOT_ENROLL_SIGNATURE_TO_DBX 0x0d +#define SECUREBOOT_DELETE_SIGNATURE_FROM_DBX 0x0e +#define FORM_FILE_EXPLORER_ID 0x0f +#define FORM_FILE_EXPLORER_ID_PK 0x10 +#define FORM_FILE_EXPLORER_ID_KEK 0x11 +#define FORM_FILE_EXPLORER_ID_DB 0x12 +#define FORM_FILE_EXPLORER_ID_DBX 0x13 + +#define SECURE_BOOT_MODE_CUSTOM 0x01 +#define SECURE_BOOT_MODE_STANDARD 0x00 + +#define KEY_SECURE_BOOT_ENABLE 0x1000 +#define KEY_SECURE_BOOT_MODE 0x1001 +#define KEY_VALUE_SAVE_AND_EXIT_DB 0x1002 +#define KEY_VALUE_NO_SAVE_AND_EXIT_DB 0x1003 +#define KEY_VALUE_SAVE_AND_EXIT_PK 0x1004 +#define KEY_VALUE_NO_SAVE_AND_EXIT_PK 0x1005 +#define KEY_VALUE_SAVE_AND_EXIT_KEK 0x1008 +#define KEY_VALUE_NO_SAVE_AND_EXIT_KEK 0x1009 +#define KEY_VALUE_SAVE_AND_EXIT_DBX 0x100a +#define KEY_VALUE_NO_SAVE_AND_EXIT_DBX 0x100b + +#define KEY_SECURE_BOOT_OPTION 0x1100 +#define KEY_SECURE_BOOT_PK_OPTION 0x1101 +#define KEY_SECURE_BOOT_KEK_OPTION 0x1102 +#define KEY_SECURE_BOOT_DB_OPTION 0x1103 +#define KEY_SECURE_BOOT_DBX_OPTION 0x1104 +#define KEY_SECURE_BOOT_DELETE_PK 0x1105 +#define KEY_ENROLL_PK 0x1106 +#define KEY_ENROLL_KEK 0x1107 +#define KEY_DELETE_KEK 0x1108 +#define KEY_SECURE_BOOT_KEK_GUID 0x110a +#define KEY_SECURE_BOOT_SIGNATURE_GUID_DB 0x110b +#define KEY_SECURE_BOOT_SIGNATURE_GUID_DBX 0x110c + +#define LABEL_KEK_DELETE 0x1200 +#define LABEL_DB_DELETE 0x1201 +#define LABEL_DBX_DELETE 0x1202 +#define LABEL_END 0xffff + +#define SECURE_BOOT_MAX_ATTEMPTS_NUM 255 + +#define CONFIG_OPTION_OFFSET 0x2000 + +#define OPTION_CONFIG_QUESTION_ID 0x2000 +#define OPTION_CONFIG_RANGE 0x1000 + +// +// Question ID 0x2000 ~ 0x2FFF is for KEK +// +#define OPTION_DEL_KEK_QUESTION_ID 0x2000 +// +// Question ID 0x3000 ~ 0x3FFF is for DB +// +#define OPTION_DEL_DB_QUESTION_ID 0x3000 +// +// Question ID 0x4000 ~ 0x4FFF is for DBX +// +#define OPTION_DEL_DBX_QUESTION_ID 0x4000 + + +#define FILE_OPTION_OFFSET 0x8000 +#define FILE_OPTION_MASK 0x7FFF + +#define SECURE_BOOT_GUID_SIZE 36 +#define SECURE_BOOT_GUID_STORAGE_SIZE 37 + + +// +// Nv Data structure referenced by IFR +// +typedef struct { + BOOLEAN SecureBootState; //Secure Boot Disable/Enable; + BOOLEAN HideSecureBoot; //Hiden Attempt Secure Boot + CHAR16 SignatureGuid[SECURE_BOOT_GUID_STORAGE_SIZE]; + BOOLEAN PhysicalPresent; //If a Physical Present User; + UINT8 SecureBootMode; //Secure Boot Mode: Standard Or Custom + BOOLEAN DeletePk; + BOOLEAN HasPk; //If Pk is existed it is true; +} SECUREBOOT_CONFIGURATION; + +#endif diff --git a/OvmfPkg/SecureBootConfigDxe/SecureBootConfigStrings.uni b/OvmfPkg/SecureBootConfigDxe/SecureBootConfigStrings.uni new file mode 100644 index 0000000000000000000000000000000000000000..ed4db131e9b0dd8547b4cf22e3915a25fee3abd1 GIT binary patch literal 9518 zcmcIq+iu%N5S`Z+=syt7OIuWSP6XSMAj_@uB*-_#h-Dj+oXgKAJ!i)& zlG-JANvj|za_?u)&dkm%_3i7H{ERD+zvW7<$2l*c9M2=-4GvwXM1gQ&@u*NO! z1@1e%&5?hFx0$JZDd+Nl_e-R9k$Z=FiR_u0Y&kKd<7I2xb}E}@OpeRi_wvPzJCXOM zhab`JPv~h|ewF9A5@{?`+wu$EJHWEQxHoub4>R<^-*l`^lr&M!8l02%P5i_=$32se z_`Lv@S3p0I*9OxN7_QAc?@{9p?bz!S?Zz1M0?!3%aK>YxJV%Ww#%9?Uv{UA$NE02$ z9RmSJ?4S2g-bx$e^&ulYd4u1k93kBSg9$j~bBNpyr04{1ZNuw{bn$E> zpB!ipDd!zXZ5uU?P0u~NQCj)CfhYTAuN!#onlw|Cd*b;QW$dwMMoW-xVicn4BEN$k z*}i8+9w0^B%;R`N)M6cusI~S{mo4And4Lk4=1A?wQFI1vIbHUX_TB*xeMk_;Y-Mzs z_GN3y-!t$_$($I;=8AKT8bHsUHqe%3T!T4y-^jGHQl(m@ERW1g_RyNM+Qm$In9<10 zY6vV`sj@3Y^8i#6BU^bq$H=Q@*A(-!r542Cr9>Qpy)vvU3*+rWzNwRQ)P7~yRGaV` z=>?=eK?yA-XGOg!njf{t>h2t?8D5DlR^bp=Xb%4J@XW#pDAiULMj2^PU8QsmOVEW8 zG{Fejq>V4;E`I&97~>=$jFI|d_lPa%A@#_nQ+r>u>Q|T@?WykL^%TKjklYkkp0L^Q5d>+g5drnplgLSAIsa zkCoEhC(HviwoJwotoz(BKtFsRZ?xVqy4jR}3M4#>&`MMO8OD7KF6lG-B)=X`dLCqy z{sq07JR*N8gp)o6V}dCzm9IS`U)+_|ceQ?U8-6Hjl=SBw@ z4aDIsvocm1m09{|^att7#du0Fn5|UOQ~V6AzA=6_W0M#;_3zq8KuJqIGQMWdc$cnB zgwSmidN@bG$mptky^DN`6kXZQ{d9CMjRZWv0?>P7~8aUw&Eb8Q)SPsXRy7 zR8?F>URp2bo7a=yEaL3Goy8l&BzLduF0C;}p5M56aL=GbPoH2j^0Q)W>x%;a&vhuX z!$r2Fk63#IS!aAwEJI<`?1!;_Hgc;c9WElDjD!(oeH%t28hNU}%rWYrJHW0GW-N?O z`&kcTK1?oWVN7L==@|7mYat$9hm5hG^)Tila`}q2K-Pa=l`%K|sn6bNkiYQia?Yn~ zP&|L;0PgEL9C7&t5~8!^Pt=Q;aAMkGtz-nN*akds>md zlg1Njd9BA@j4@jh#+$}!x;FeClSYxnsQliJk6jmW7?qE&da-W)L}&f-x4LtE2<%)g zo>cz6gZ`IYVcr-K^84D{MBnOhts*=y=k`7LX8htZlTTQ2t^Wb(OZW)sX<({P)pR^2 zdbBeQ&&rjCs&>cj=XT7{vnr;T{Wq^0)+;EB5wj@c5QQv{jN#;?t0)Qf${hjC=r#&Hn