OcBootManagementLib: Initial privilege/password support

This commit is contained in:
Download-Fritz 2019-09-28 16:00:41 +02:00
parent eedf63f106
commit f2a92fff9b
6 changed files with 245 additions and 20 deletions

View File

@ -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
);
/**

View File

@ -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(_, __) \

View File

@ -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.
//

View File

@ -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.

View File

@ -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"));

View File

@ -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),