Skip to content

Commit

Permalink
Add parameter processing for loading of binaries
Browse files Browse the repository at this point in the history
* Also report the SHA-256 of embedded files with '-i' and add a '-h' option.
* Also improve argc/argv parameter conversion and add double quotes support.
* Also make sure to always use UEFI 2.0 protocol terminology.
  • Loading branch information
pbatard committed Sep 11, 2024
1 parent 4cd39e8 commit 7d87c2b
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 53 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ And it does so by making incredibly **easy** to install your own set of Secure B
5. Once the installation is complete, reboot into UEFI firmware settings, and make sure that
Secure Boot is enabled.

If needed, you can also provide your own DB/DBX/DBT/KEK/PK/MOK binaries in DER, PEM, ESL or
signed ESL format, by using something like `-db canonical_ca.cer` to point a Secure Boot
variable to the data you want to install for it.

## Compilation

Because Mosby depends on OpenSSL to provide the various cryptography function it needs, and
Expand Down
10 changes: 6 additions & 4 deletions src/console.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ EFI_STATUS ConsolePrintBoxAt(
)
{
INTN i;
SIMPLE_TEXT_OUTPUT_INTERFACE *Console = gST->ConOut;
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Console = gST->ConOut;
UINTN Rows, Cols;
CHAR16 *Line;

Expand Down Expand Up @@ -196,8 +196,9 @@ VOID ConsolePrintBox(
)
{
EFI_SIMPLE_TEXT_OUTPUT_MODE SavedConsoleMode;
SIMPLE_TEXT_OUTPUT_INTERFACE *Console = gST->ConOut;
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Console = gST->ConOut;
CopyMem(&SavedConsoleMode, Console->Mode, sizeof(SavedConsoleMode));
Console->ClearScreen(Console);
Console->EnableCursor(Console, FALSE);
Console->SetAttribute(Console, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);

Expand All @@ -219,7 +220,7 @@ INTN ConsoleSelect(
)
{
EFI_SIMPLE_TEXT_OUTPUT_MODE SavedConsoleMode;
SIMPLE_TEXT_OUTPUT_INTERFACE *Console = gST->ConOut;
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Console = gST->ConOut;
EFI_INPUT_KEY k;
INTN Selector;
INTN SelectorLines = CountLines(Selectors);
Expand Down Expand Up @@ -265,6 +266,7 @@ INTN ConsoleSelect(
}

CopyMem(&SavedConsoleMode, Console->Mode, sizeof(SavedConsoleMode));
Console->ClearScreen(Console);
Console->EnableCursor(Console, FALSE);
Console->SetAttribute(Console, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);

Expand Down Expand Up @@ -367,7 +369,7 @@ VOID ConsoleError(

VOID ConsoleReset(VOID)
{
SIMPLE_TEXT_OUTPUT_INTERFACE *Console = gST->ConOut;
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Console = gST->ConOut;

Console->Reset(Console, TRUE);
// Set mode 0 - required to be 80x25
Expand Down
8 changes: 4 additions & 4 deletions src/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
STATIC EFI_STATUS GeneratePath(
IN CONST CHAR16* Name,
IN CONST EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
OUT EFI_DEVICE_PATH **Path,
OUT EFI_DEVICE_PATH_PROTOCOL **Path,
OUT CHAR16 **PathName)
{
UINTN PathLen;
Expand Down Expand Up @@ -94,7 +94,7 @@ EFI_STATUS SimpleFileOpenByHandle(
)
{
EFI_STATUS Status;
EFI_FILE_IO_INTERFACE *Drive;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Drive;
EFI_FILE_HANDLE Root;

Status = gBS->HandleProtocol(DeviceHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID**)&Drive);
Expand Down Expand Up @@ -123,7 +123,7 @@ EFI_STATUS SimpleFileOpen(
EFI_STATUS Status;
EFI_HANDLE Device;
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
EFI_DEVICE_PATH *LoadPath = NULL;
EFI_DEVICE_PATH_PROTOCOL *LoadPath = NULL;
CHAR16 *PathName = NULL;

Status = gBS->HandleProtocol(Image, &gEfiLoadedImageProtocolGuid, (VOID**)&LoadedImage);
Expand Down Expand Up @@ -302,7 +302,7 @@ EFI_STATUS SimpleVolumeSelector(
EFI_FILE_SYSTEM_INFO *FsInfo = (VOID *)Buffer;
EFI_FILE_HANDLE Root;
CHAR16 *Name;
EFI_FILE_IO_INTERFACE *Drive;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Drive;

Status = gBS->HandleProtocol(VolumeHandles[i], &gEfiSimpleFileSystemProtocolGuid, (VOID**)&Drive);
if (EFI_ERROR(Status) || Drive == NULL)
Expand Down
2 changes: 1 addition & 1 deletion src/gen_data.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ declare -A source=(

# From https://uefi.org/revocationlistfile.
# Needs to be updated manually on DBX update since Microsoft stupidly decided to
# hardcode the EFI_TIME timestamp of the authenticated list updates to 2010.03.06
# hardcode the EFI_TIME timestamp of ALL authenticated list updates to 2010.03.06
# instead of using the actual timestamp of when they created the variables.
declare -A archdate=(
[x64]='2023.05.09'
Expand Down
90 changes: 60 additions & 30 deletions src/mosby.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,36 +37,43 @@ STATIC EFI_GUID gEfiShimLockGuid =
/* Attributes for the "key" types we support */
STATIC struct {
CHAR8 *DisplayName;
CHAR16 *OptionName;
CHAR16 *VariableName;
EFI_GUID *VariableGuid;
} KeyInfo[MAX_TYPES] = {
[PK] = {
.DisplayName = "PK",
.DisplayName = "PK: ",
.OptionName = L"-pk",
.VariableName = EFI_PLATFORM_KEY_NAME,
.VariableGuid = &gEfiGlobalVariableGuid,
},
[KEK] = {
.DisplayName = "KEK",
.DisplayName = "KEK:",
.OptionName = L"-kek",
.VariableName = EFI_KEY_EXCHANGE_KEY_NAME,
.VariableGuid = &gEfiGlobalVariableGuid,
},
[DB] = {
.DisplayName = "DB",
.DisplayName = "DB: ",
.OptionName = L"-db",
.VariableName = EFI_IMAGE_SECURITY_DATABASE,
.VariableGuid = &gEfiImageSecurityDatabaseGuid,
},
[DBX] = {
.DisplayName = "DBX",
.DisplayName = "DBX:",
.OptionName = L"-dbx",
.VariableName = EFI_IMAGE_SECURITY_DATABASE1,
.VariableGuid = &gEfiImageSecurityDatabaseGuid,
},
[DBT] = {
.DisplayName = "DBT",
.DisplayName = "DBT:",
.OptionName = L"-dbt",
.VariableName = EFI_IMAGE_SECURITY_DATABASE2,
.VariableGuid = &gEfiImageSecurityDatabaseGuid,
},
[MOK] = {
.DisplayName = "MOK",
.DisplayName = "MOK:",
.OptionName = L"-mok",
.VariableName = L"MokList",
.VariableGuid = &gEfiShimLockGuid,
}
Expand All @@ -84,16 +91,15 @@ EFI_STATUS EFIAPI efi_main(
CONST UINT32 Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS |
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
BOOLEAN TestMode = FALSE, GenDBCred = FALSE, Append;
EFI_STATUS Status, SetStatus;
EFI_STATUS Status;
EFI_TIME Time;
UINTN i;
UINTN i, NumPKs;
INTN Argc, Type, Sel;
MOSBY_CRED Cred;
CHAR8 DbSubject[80], PkSubject[80];
CHAR16 **Argv = NULL, **ArgvCopy, MosbyKeyPath[MAX_PATH];
MOSBY_LIST List;

ConsoleReset();
RecallPrint(L"Mosby %s %a\n", ARCH_EXT, VERSION_STRING);
gBaseImageHandle = BaseImageHandle;
gRT->GetTime(&Time, NULL);
Expand All @@ -107,7 +113,7 @@ EFI_STATUS EFIAPI efi_main(
Status = ArgSplit(gBaseImageHandle, &Argc, &Argv);
if (Status == EFI_SUCCESS) {
ArgvCopy = Argv;
while (Argc > 1 && ArgvCopy[1][0] == L'-') {
while (Argc > 1) {
if (StrCmp(ArgvCopy[1], L"-t") == 0) {
TestMode = TRUE;
ArgvCopy += 1;
Expand All @@ -116,21 +122,42 @@ EFI_STATUS EFIAPI efi_main(
gOptionSilent = TRUE;
ArgvCopy += 1;
Argc -= 1;
} else if (StrCmp(ArgvCopy[1], L"-h") == 0) {
Print(L"Usage: Mosby [-i] [-h] [-s] [-v] [-{var} <file>] [-{var} <file>] [...]\n");
Print(L" Supported {var} values: pk, kek, db, dbx, dbt, mok\n");
goto exit;
} else if (StrCmp(ArgvCopy[1], L"-v") == 0) {
goto exit;
} else if (StrCmp(ArgvCopy[1], L"-i") == 0) {
Print(L"\nThis version includes:\n");
for (i = 0; i < List.Size; i++)
Print(L"o %a:\t%a\n\tFrom %a\n", KeyInfo[List.Entry[i].Type].DisplayName,
List.Entry[i].Description, List.Entry[i].Url);
for (i = 0; i < List.Size; i++) {
if (List.Entry[i].Description != NULL) {
Print(L"o %a %a\n From %a\n", KeyInfo[List.Entry[i].Type].DisplayName,
List.Entry[i].Description, List.Entry[i].Url);
Print(L" %a\n", Sha256ToString(List.Entry[i].Buffer.Data, List.Entry[i].Buffer.Size));
}
}
goto exit;
} else {
// Unsupported argument
break;
for (Type = 0; Type < MAX_TYPES; Type++) {
if ((Argc > 2) && StrCmp(ArgvCopy[1], KeyInfo[Type].OptionName) == 0) {
if (!SimpleFileExistsByPath(gBaseImageHandle, ArgvCopy[2])) {
Status = EFI_NOT_FOUND;
ReportErrorAndExit(L"File '%s' does not exist\n", ArgvCopy[2]);
}
List.Entry[List.Size].Type = Type;
List.Entry[List.Size].Path = ArgvCopy[2];
List.Size++;
ArgvCopy += 2;
Argc -= 2;
break;
}
}
if (Type >= MAX_TYPES) {
Status = EFI_INVALID_PARAMETER;
ReportErrorAndExit(L"Unsupported or incomplete parameter: '%s'\n", ArgvCopy[1]);
}
}
}
// TODO: Add db, dbx, etc processing
// TODO: Make sure only one PK can be provided by the user
}

/* Initialize the random generator and validate the platform */
Expand Down Expand Up @@ -181,7 +208,7 @@ EFI_STATUS EFIAPI efi_main(
L"",
L"Do you want to SELECT an existing Secure Boot signing certificate ",
L"or GENERATE new Secure Boot signing credentials (or DON'T INSTALL ",
L"any certificate for your own usage)? ",
L"an additional certificate for your own usage)? ",
L"",
L"If you don't know what to use, we recommend to GENERATE new signing",
L"credentials, so that you will be able to sign your own Secure Boot ",
Expand Down Expand Up @@ -222,8 +249,6 @@ EFI_STATUS EFIAPI efi_main(
if (List.Entry[i].Variable.Data != NULL)
continue;
if (List.Entry[i].Path != NULL && List.Entry[i].Buffer.Data == NULL) {
if (!SimpleFileExistsByPath(gBaseImageHandle, List.Entry[i].Path))
ReportErrorAndExit(L"File '%s' does not exist\n", List.Entry[i].Path);
Status = SimpleFileReadAllByPath(gBaseImageHandle, List.Entry[i].Path,
&List.Entry[i].Buffer.Size, (VOID**)&List.Entry[i].Buffer.Data);
if (EFI_ERROR(Status))
Expand Down Expand Up @@ -263,8 +288,12 @@ EFI_STATUS EFIAPI efi_main(
}

/* Generate a keyless PK cert if none was specified */
for (i = 0; i < List.Size && List.Entry[i].Type != PK; i++);
if (i == List.Size) {
for (i = 0, NumPKs = 0; i < List.Size; i++)
if (List.Entry[i].Type == PK)
NumPKs++;
if (NumPKs >= 2)
RecallPrint(L"WARNING: More than one PK was specified. Only the first will be used.");
if (NumPKs == 0) {
if (List.Size >= MOSBY_MAX_LIST_SIZE) {
Status = EFI_OUT_OF_RESOURCES;
ReportErrorAndExit(L"List size is too small\n");
Expand Down Expand Up @@ -303,16 +332,17 @@ EFI_STATUS EFIAPI efi_main(
if (List.Entry[i].Type != Type)
continue;
if (List.Entry[i].Description != NULL)
RecallPrint(L"Installing %a:\t%a\n", KeyInfo[Type].DisplayName, List.Entry[i].Description);
RecallPrint(L"Installing %a '%a'\n", KeyInfo[Type].DisplayName, List.Entry[i].Description);
else
RecallPrint(L"Installing %a:\tfrom %s\n", KeyInfo[Type].DisplayName, List.Entry[i].Path);
SetStatus = gRT->SetVariable(KeyInfo[Type].VariableName, KeyInfo[Type].VariableGuid,
RecallPrint(L"Installing %a From '%s'\n", KeyInfo[Type].DisplayName, List.Entry[i].Path);
Status = gRT->SetVariable(KeyInfo[Type].VariableName, KeyInfo[Type].VariableGuid,
Attributes | (Append ? EFI_VARIABLE_APPEND_WRITE : 0),
List.Entry[i].Variable.Size, List.Entry[i].Variable.Data);
if (EFI_ERROR(SetStatus)) {
RecallPrint(L"Failed to set Secure Boot variable: %r\n", SetStatus);
Status = SetStatus;
}
if (EFI_ERROR(Status))
ReportErrorAndExit(L"Failed to set Secure Boot variable: %r\n", Status);
// Make sure we only ever process one PK
if (List.Entry[i].Type == PK)
break;
Append = TRUE;
}
}
Expand Down
19 changes: 19 additions & 0 deletions src/pki.c
Original file line number Diff line number Diff line change
Expand Up @@ -582,3 +582,22 @@ EFI_STATUS SignToAuthVar(
FreePool(SignData);
return Status;
}

CHAR8* Sha256ToString(
CONST UINT8 *Buffer,
CONST UINTN Size
)
{
STATIC CHAR8 HashString[SHA256_DIGEST_LENGTH * 2 + 1];
UINT8 i, Hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;

SHA256_Init(&sha256);
SHA256_Update(&sha256, Buffer, Size);
SHA256_Final(Hash, &sha256);

for (i = 0; i < SHA256_DIGEST_LENGTH; i++)
AsciiSPrint(&HashString[i * 2], sizeof(HashString) - (i * 2), "%02x", Hash[i]);

return HashString;
}
5 changes: 5 additions & 0 deletions src/pki.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,8 @@ EFI_STATUS SignToAuthVar(
IN OUT MOSBY_VARIABLE *Variable,
IN CONST MOSBY_CRED *Credentials
);

CHAR8* Sha256ToString(
CONST UINT8 *Buffer,
CONST UINTN Size
);
45 changes: 31 additions & 14 deletions src/shell.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ EFI_STATUS ArgSplit(
INTN i, Count = 1;
EFI_STATUS Status;
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
CHAR16 *Start;
CHAR16 *LoadOptions;
BOOLEAN OpenQuote;

*Argc = 0;

Expand All @@ -47,31 +48,47 @@ EFI_STATUS ArgSplit(
return Status;
}

for (i = 0; i < LoadedImage->LoadOptionsSize; i += 2) {
CHAR16 *c = (CHAR16 *)(LoadedImage->LoadOptions + i);
if (*c == L' ' && *(c+1) != '\0') {
LoadOptions = (CHAR16 *)LoadedImage->LoadOptions;
OpenQuote = FALSE;
for (i = 0; i < LoadedImage->LoadOptionsSize / 2; i++) {
if (LoadOptions[i] == L'"')
OpenQuote = !OpenQuote;
else if (!OpenQuote && LoadOptions[i] == L' ' &&
LoadOptions[i + 1] != ' ' && LoadOptions[i + 1] != '\0')
(*Argc)++;
}
}

(*Argc)++; // We counted spaces, so add one for initial
(*Argc)++; // We counted parameters, so add one for initial

*Argv = AllocatePool(*Argc * sizeof(*Argv));
if (*Argv == NULL)
return EFI_OUT_OF_RESOURCES;

(*Argv)[0] = (CHAR16 *)LoadedImage->LoadOptions;
for (i = 0; i < LoadedImage->LoadOptionsSize; i += 2) {
CHAR16 *c = (CHAR16 *)(LoadedImage->LoadOptions + i);
if (*c == L' ') {
*c = L'\0';
if (*(c + 1) == '\0')
OpenQuote = FALSE;
for (i = 0; i < LoadedImage->LoadOptionsSize / 2 - 1; i++) {
if (OpenQuote) {
if (LoadOptions[i] == L'"') {
OpenQuote = FALSE;
LoadOptions[i] = L'\0';
// If we are closing a quote with an empty parameter, remove that parameter
if (&LoadOptions[i] == (*Argv)[Count - 1])
Count--;
}
} else if (LoadOptions[i] == L' ' && LoadOptions[i + 1] != L' ') {
LoadOptions[i] = L'\0';
if (LoadOptions[i + 1] == L'"') {
OpenQuote = TRUE;
LoadOptions[++i] = L'\0';
}
if (LoadOptions[i + 1] == L'\0')
// Strip trailing space
break;
Start = c + 1;
(*Argv)[Count++] = Start;
}
(*Argv)[Count++] = &LoadOptions[i + 1];
} else if (LoadOptions[i] == L' ')
LoadOptions[i] = L'\0';
}
*Argc = Count;

return EFI_SUCCESS;
}
Expand Down

0 comments on commit 7d87c2b

Please sign in to comment.