From f2a92fff9b0e5857e6d49a98d98a0e2633d433d2 Mon Sep 17 00:00:00 2001 From: Download-Fritz Date: Sat, 28 Sep 2019 16:00:41 +0200 Subject: [PATCH] OcBootManagementLib: Initial privilege/password support --- Include/Library/OcBootManagementLib.h | 59 ++++++- Include/Library/OcConfigurationLib.h | 15 +- Library/OcAppleBootCompatLib/CustomSlide.c | 2 +- Library/OcBootManagementLib/BootArguments.c | 25 ++- .../OcBootManagementLib/OcBootManagementLib.c | 161 +++++++++++++++++- .../OcConfigurationLib/OcConfigurationLib.c | 3 + 6 files changed, 245 insertions(+), 20 deletions(-) diff --git a/Include/Library/OcBootManagementLib.h b/Include/Library/OcBootManagementLib.h index 50671d22..e651ca1a 100755 --- a/Include/Library/OcBootManagementLib.h +++ b/Include/Library/OcBootManagementLib.h @@ -305,6 +305,24 @@ typedef struct { CONST CHAR8 *Arguments; } OC_PICKER_ENTRY; +/** + Privilege levels to escalate to +**/ +typedef enum { + OcPrivilegeUnauthorized = 0, + OcPrivilegeAuthorized = 1 +} OC_PRIVILEGE_LEVEL; + +/** + Request a privilege escalation, for example by prompting for a password. +**/ +typedef +EFI_STATUS +(EFIAPI *OC_REQ_PRIVILEGE)( + IN VOID *Context, + IN OC_PRIVILEGE_LEVEL Level + ); + /** Picker behaviour action. **/ @@ -358,6 +376,14 @@ typedef struct { // EFI_HANDLE ExcludeHandle; // + // Privilege escalation requesting routine. + // + OC_REQ_PRIVILEGE RequestPrivilege; + // + // Context to pass to RequestPrivilege, optional. + // + VOID *PrivilegeContext; + // // Enable polling boot arguments. // BOOLEAN PollAppleHotKeys; @@ -473,6 +499,31 @@ OcGetDefaultBootEntry ( IN UINTN NumBootEntries ); +typedef struct { + OC_PRIVILEGE_LEVEL CurrentLevel; + CONST UINT8 *Salt; + UINT32 SaltSize; + CONST UINT8 *Hash; +} OC_PRIVILEGE_CONTEXT; + +/** + Show simple password prompt and return verification status. + + @param[in] Context Privilege context. + @param[in] Level The privilege level to request escalating to. + + @retval EFI_SUCCESS The privilege level has been escalated successfully. + @retval EFI_ABORTED The privilege escalation has been aborted. + @retval other The system must be considered compromised. + +**/ +EFI_STATUS +EFIAPI +OcShowSimplePasswordRequest ( + IN VOID *Context, + IN OC_PRIVILEGE_LEVEL Level + ); + /** Show simple boot entry selection menu and return chosen entry. @@ -697,6 +748,7 @@ OcRemoveArgumentFromCmd ( /** Append argument to command line without deduplication. + @param[in, out] Context Picker context. NULL, if a privilege escalation is not required. @param[in, out] CommandLine Argument command line of BOOT_LINE_LENGTH bytes. @param[in] Argument Argument, e.g. -v, slide=0, debug=0x100, etc. @param[in] ArgumentLength Argument length, e.g. L_STR_LEN ("-v"). @@ -705,9 +757,10 @@ OcRemoveArgumentFromCmd ( **/ BOOLEAN OcAppendArgumentToCmd ( - IN OUT CHAR8 *CommandLine, - IN CONST CHAR8 *Argument, - IN CONST UINTN ArgumentLength + IN OUT OC_PICKER_CONTEXT *Context OPTIONAL, + IN OUT CHAR8 *CommandLine, + IN CONST CHAR8 *Argument, + IN CONST UINTN ArgumentLength ); /** diff --git a/Include/Library/OcConfigurationLib.h b/Include/Library/OcConfigurationLib.h index 650154b3..53a8ac2e 100644 --- a/Include/Library/OcConfigurationLib.h +++ b/Include/Library/OcConfigurationLib.h @@ -272,12 +272,15 @@ #define OCS_EXPOSE_VERSION 2U #define OC_MISC_SECURITY_FIELDS(_, __) \ - _(UINT32 , ScanPolicy , , OC_SCAN_DEFAULT_POLICY , ()) \ - _(BOOLEAN , AllowNvramReset , , FALSE , ()) \ - _(BOOLEAN , ExposeSensitiveData , , OCS_EXPOSE_VERSION , ()) \ - _(BOOLEAN , RequireVault , , TRUE , ()) \ - _(BOOLEAN , RequireSignature , , TRUE , ()) \ - _(UINT64 , HaltLevel , , 0x80000000 , ()) + _(UINT32 , ScanPolicy , , OC_SCAN_DEFAULT_POLICY , ()) \ + _(BOOLEAN , AllowNvramReset , , FALSE , ()) \ + _(BOOLEAN , ExposeSensitiveData , , OCS_EXPOSE_VERSION , ()) \ + _(BOOLEAN , EnablePassword , , FALSE , ()) \ + _(UINT8 , PasswordHash , [64] , {0} , ()) \ + _(OC_DATA , PasswordSalt , , OC_EDATA_CONSTR (_, __) , OC_DESTR (OC_DATA)) \ + _(BOOLEAN , RequireVault , , TRUE , ()) \ + _(BOOLEAN , RequireSignature , , TRUE , ()) \ + _(UINT64 , HaltLevel , , 0x80000000 , ()) OC_DECLARE (OC_MISC_SECURITY) #define OC_MISC_TOOLS_ENTRY_FIELDS(_, __) \ diff --git a/Library/OcAppleBootCompatLib/CustomSlide.c b/Library/OcAppleBootCompatLib/CustomSlide.c index f3f326e6..c73aded5 100644 --- a/Library/OcAppleBootCompatLib/CustomSlide.c +++ b/Library/OcAppleBootCompatLib/CustomSlide.c @@ -499,7 +499,7 @@ GetVariableBootArgs ( // AsciiSPrint (SlideArgument, ARRAY_SIZE (SlideArgument), "slide=%-03d", Slide); - if (!OcAppendArgumentToCmd (SlideSupport->BootArgs, SlideArgument, SlideArgumentLength)) { + if (!OcAppendArgumentToCmd (NULL, SlideSupport->BootArgs, SlideArgument, SlideArgumentLength)) { // // Broken boot-args, try to overwrite. // diff --git a/Library/OcBootManagementLib/BootArguments.c b/Library/OcBootManagementLib/BootArguments.c index 14bda653..504f285f 100644 --- a/Library/OcBootManagementLib/BootArguments.c +++ b/Library/OcBootManagementLib/BootArguments.c @@ -131,12 +131,29 @@ OcRemoveArgumentFromCmd ( BOOLEAN OcAppendArgumentToCmd ( - IN OUT CHAR8 *CommandLine, - IN CONST CHAR8 *Argument, - IN CONST UINTN ArgumentLength + IN OUT OC_PICKER_CONTEXT *Context OPTIONAL, + IN OUT CHAR8 *CommandLine, + IN CONST CHAR8 *Argument, + IN CONST UINTN ArgumentLength ) { - UINTN Len = AsciiStrLen (CommandLine); + EFI_STATUS Status; + UINTN Len = AsciiStrLen (CommandLine); + + if (Context != NULL) { + Status = Context->RequestPrivilege ( + Context->PrivilegeContext, + OcPrivilegeAuthorized + ); + if (EFI_ERROR (Status)) { + if (Status != EFI_ABORTED) { + ASSERT (FALSE); + return FALSE; + } + + return TRUE; + } + } // // Account for extra space. diff --git a/Library/OcBootManagementLib/OcBootManagementLib.c b/Library/OcBootManagementLib/OcBootManagementLib.c index 03abb0d6..c17a685b 100644 --- a/Library/OcBootManagementLib/OcBootManagementLib.c +++ b/Library/OcBootManagementLib/OcBootManagementLib.c @@ -961,7 +961,7 @@ OcWaitForAppleKeyIndex ( if (HasShift) { if (OcGetArgumentFromCmd (Context->AppleBootArgs, "-x", L_STR_LEN ("-x")) == NULL) { DEBUG ((DEBUG_INFO, "OCB: Shift means -x\n")); - OcAppendArgumentToCmd (Context->AppleBootArgs, "-x", L_STR_LEN ("-x")); + OcAppendArgumentToCmd (Context, Context->AppleBootArgs, "-x", L_STR_LEN ("-x")); } continue; } @@ -972,7 +972,7 @@ OcWaitForAppleKeyIndex ( if (HasCommand && HasKeyV) { if (OcGetArgumentFromCmd (Context->AppleBootArgs, "-v", L_STR_LEN ("-v")) == NULL) { DEBUG ((DEBUG_INFO, "OCB: CMD+V means -v\n")); - OcAppendArgumentToCmd (Context->AppleBootArgs, "-v", L_STR_LEN ("-v")); + OcAppendArgumentToCmd (Context, Context->AppleBootArgs, "-v", L_STR_LEN ("-v")); } continue; } @@ -983,7 +983,7 @@ OcWaitForAppleKeyIndex ( if (HasCommand && HasKeyC && HasKeyMinus) { if (OcGetArgumentFromCmd (Context->AppleBootArgs, "-no_compat_check", L_STR_LEN ("-no_compat_check")) == NULL) { DEBUG ((DEBUG_INFO, "OCB: CMD+C+MINUS means -no_compat_check\n")); - OcAppendArgumentToCmd (Context->AppleBootArgs, "-no_compat_check", L_STR_LEN ("-no_compat_check")); + OcAppendArgumentToCmd (Context, Context->AppleBootArgs, "-no_compat_check", L_STR_LEN ("-no_compat_check")); } continue; } @@ -994,7 +994,7 @@ OcWaitForAppleKeyIndex ( if (HasCommand && HasKeyK) { if (AsciiStrStr (Context->AppleBootArgs, "kcsuffix=release") == NULL) { DEBUG ((DEBUG_INFO, "OCB: CMD+K means kcsuffix=release\n")); - OcAppendArgumentToCmd (Context->AppleBootArgs, "kcsuffix=release", L_STR_LEN ("kcsuffix=release")); + OcAppendArgumentToCmd (Context, Context->AppleBootArgs, "kcsuffix=release", L_STR_LEN ("kcsuffix=release")); } continue; } @@ -1028,11 +1028,11 @@ OcWaitForAppleKeyIndex ( if (WantsZeroSlide) { if (AsciiStrStr (Context->AppleBootArgs, "slide=0") == NULL) { DEBUG ((DEBUG_INFO, "OCB: CMD+S+MINUS means slide=0\n")); - OcAppendArgumentToCmd (Context->AppleBootArgs, "slide=0", L_STR_LEN ("slide=0")); + OcAppendArgumentToCmd (Context, Context->AppleBootArgs, "slide=0", L_STR_LEN ("slide=0")); } } else if (OcGetArgumentFromCmd (Context->AppleBootArgs, "-s", L_STR_LEN ("-s")) == NULL) { DEBUG ((DEBUG_INFO, "OCB: CMD+S means -s\n")); - OcAppendArgumentToCmd (Context->AppleBootArgs, "-s", L_STR_LEN ("-s")); + OcAppendArgumentToCmd (Context, Context->AppleBootArgs, "-s", L_STR_LEN ("-s")); } continue; } @@ -1062,6 +1062,140 @@ OcWaitForAppleKeyIndex ( return OC_INPUT_TIMEOUT; } +EFI_STATUS +EFIAPI +OcShowSimplePasswordRequest ( + IN VOID *Context, + IN OC_PRIVILEGE_LEVEL Level + ) +{ + OC_PRIVILEGE_CONTEXT *Privilege; + + BOOLEAN Result; + + UINT8 Password[32]; + UINT32 PwIndex; + + UINT8 Index; + EFI_STATUS Status; + EFI_INPUT_KEY Key; + + if (Context == NULL) { + return EFI_SUCCESS; + } + + Privilege = (OC_PRIVILEGE_CONTEXT *)Context; + + if (Privilege->CurrentLevel >= Level) { + return EFI_SUCCESS; + } + + gST->ConOut->ClearScreen (gST->ConOut); + + for (Index = 0; Index < 3; ++Index) { + PwIndex = 0; + // + // Skip previously pressed characters. + // + do { + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + } while (!EFI_ERROR (Status)); + + gST->ConOut->OutputString (gST->ConOut, L"Password: "); + + while (TRUE) { + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + if (Status == EFI_NOT_READY) { + continue; + } else if (EFI_ERROR (Status)) { + gST->ConOut->ClearScreen (gST->ConOut); + ZeroMem (Password, PwIndex); + ZeroMem (&Key.UnicodeChar, sizeof (Key.UnicodeChar)); + + DEBUG ((DEBUG_ERROR, "Input device error\r\n")); + return EFI_ABORTED; + } + + if (Key.ScanCode == SCAN_ESC) { + gST->ConOut->ClearScreen (gST->ConOut); + ZeroMem (Password, PwIndex); + // + // ESC aborts the input. + // + return EFI_ABORTED; + } else if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { + gST->ConOut->ClearScreen (gST->ConOut); + // + // RETURN finalizes the input. + // + break; + } else if (Key.UnicodeChar == CHAR_BACKSPACE) { + // + // Delete the last entered character, if such exists. + // + if (PwIndex != 0) { + --PwIndex; + Password[PwIndex] = 0; + // + // Overwrite current character with a space. + // + gST->ConOut->SetCursorPosition ( + gST->ConOut, + gST->ConOut->Mode->CursorColumn - 1, + gST->ConOut->Mode->CursorRow + ); + gST->ConOut->OutputString (gST->ConOut, L" "); + gST->ConOut->SetCursorPosition ( + gST->ConOut, + gST->ConOut->Mode->CursorColumn - 1, + gST->ConOut->Mode->CursorRow + ); + } + + continue; + } else if (Key.UnicodeChar == CHAR_NULL + || (UINT8)Key.UnicodeChar != Key.UnicodeChar) { + // + // Only ASCII characters are supported. + // + continue; + } + + if (PwIndex == ARRAY_SIZE (Password)) { + continue; + } + + gST->ConOut->OutputString (gST->ConOut, L"*"); + + Password[PwIndex] = (UINT8)Key.UnicodeChar; + ++PwIndex; + } + + Result = OcVerifyPasswordSha512 ( + Password, + PwIndex, + Privilege->Salt, + Privilege->SaltSize, + Privilege->Hash + ); + + ZeroMem (Password, PwIndex); + + if (Result) { + gST->ConOut->ClearScreen (gST->ConOut); + Privilege->CurrentLevel = Level; + return EFI_SUCCESS; + } + } + + gST->ConOut->ClearScreen (gST->ConOut); + DEBUG ((DEBUG_WARN, "Password retry limit exceeded.\r\n")); + + gBS->Stall (5000000); + gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL); + return EFI_ACCESS_DENIED; +} + EFI_STATUS OcRunSimpleBootPicker ( IN OC_PICKER_CONTEXT *Context @@ -1080,6 +1214,21 @@ OcRunSimpleBootPicker ( return EFI_NOT_FOUND; } + if (Context->PickerCommand != OcPickerDefault) { + Status = Context->RequestPrivilege ( + Context->PrivilegeContext, + OcPrivilegeAuthorized + ); + if (EFI_ERROR (Status)) { + if (Status != EFI_ABORTED) { + ASSERT (FALSE); + return Status; + } + + Context->PickerCommand = OcPickerDefault; + } + } + while (TRUE) { DEBUG ((DEBUG_INFO, "OCB: Performing OcScanForBootEntries...\n")); diff --git a/Library/OcConfigurationLib/OcConfigurationLib.c b/Library/OcConfigurationLib/OcConfigurationLib.c index 8947525f..dfa61188 100644 --- a/Library/OcConfigurationLib/OcConfigurationLib.c +++ b/Library/OcConfigurationLib/OcConfigurationLib.c @@ -321,8 +321,11 @@ STATIC OC_SCHEMA mMiscConfigurationSecuritySchema[] = { OC_SCHEMA_BOOLEAN_IN ("AllowNvramReset", OC_GLOBAL_CONFIG, Misc.Security.AllowNvramReset), + OC_SCHEMA_BOOLEAN_IN ("EnablePassword", OC_GLOBAL_CONFIG, Misc.Security.EnablePassword), OC_SCHEMA_INTEGER_IN ("ExposeSensitiveData", OC_GLOBAL_CONFIG, Misc.Security.ExposeSensitiveData), OC_SCHEMA_INTEGER_IN ("HaltLevel", OC_GLOBAL_CONFIG, Misc.Security.HaltLevel), + OC_SCHEMA_DATAF_IN ("PasswordHash", OC_GLOBAL_CONFIG, Misc.Security.PasswordHash), + OC_SCHEMA_DATA_IN ("PasswordSalt", OC_GLOBAL_CONFIG, Misc.Security.PasswordSalt), OC_SCHEMA_BOOLEAN_IN ("RequireSignature", OC_GLOBAL_CONFIG, Misc.Security.RequireSignature), OC_SCHEMA_BOOLEAN_IN ("RequireVault", OC_GLOBAL_CONFIG, Misc.Security.RequireVault), OC_SCHEMA_INTEGER_IN ("ScanPolicy", OC_GLOBAL_CONFIG, Misc.Security.ScanPolicy),