Skip to content

Commit

Permalink
Fix support for OVMF and other more restrictive platforms
Browse files Browse the repository at this point in the history
* It looks like some platforms do not accept an unsigned ESL/AuthVar for the PK
  but insist on the UEFI "Trust me, bro!" equivalent of a self signed AuthVar...
* We therefore switch to using authenticated variables everywhere and add self
  signing for the PK one. We also add support for loading '.auth' for people who
  want to provide their own PK on such platforms.
* Also fix the wrong use of gEfiCertX509Sha###Guid since these apply for SHA-###
  hashes only. Unconditionally use gEfiCertX509Guid instead.
  • Loading branch information
pbatard committed Sep 3, 2024
1 parent eeb9ed0 commit dd9d43d
Show file tree
Hide file tree
Showing 8 changed files with 271 additions and 165 deletions.
4 changes: 1 addition & 3 deletions MosbyPkg.inf
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,7 @@

[Guids]
gEfiCertPkcs7Guid
gEfiCertX509Sha256Guid
gEfiCertX509Sha384Guid
gEfiCertX509Sha512Guid
gEfiCertX509Guid
gEfiGlobalVariableGuid
gEfiImageSecurityDatabaseGuid
gEfiFileInfoGuid
Expand Down
2 changes: 1 addition & 1 deletion build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ else
fi
# DISABLED = SecureBoot=0, SetupMode=0
# SETUP = SecureBoot=0, SetupMode=1
SB_MODE=DISABLED
SB_MODE=SETUP
cp OVMF_VARS_4M.secboot.$SB_MODE.fd OVMF_VARS_4M.secboot.fd
export QEMU_CMD="qemu-system-x86_64 $CPU_OPT -m 1024 -M q35 -L . \
-drive if=pflash,format=raw,unit=0,file=OVMF_CODE_4M.secboot.fd,readonly=on \
Expand Down
99 changes: 54 additions & 45 deletions src/mosby.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,39 +36,39 @@ STATIC EFI_GUID gEfiShimLockGuid =

/* Attributes for the "key" types we support */
STATIC struct {
CHAR8 *Name;
CHAR16 *VarName;
EFI_GUID *VarGuid;
CHAR8 *DisplayName;
CHAR16 *VariableName;
EFI_GUID *VariableGuid;
} KeyInfo[MAX_TYPES] = {
[PK] = {
.Name = "PK",
.VarName = EFI_PLATFORM_KEY_NAME,
.VarGuid = &gEfiGlobalVariableGuid,
.DisplayName = "PK",
.VariableName = EFI_PLATFORM_KEY_NAME,
.VariableGuid = &gEfiGlobalVariableGuid,
},
[KEK] = {
.Name = "KEK",
.VarName = EFI_KEY_EXCHANGE_KEY_NAME,
.VarGuid = &gEfiGlobalVariableGuid,
.DisplayName = "KEK",
.VariableName = EFI_KEY_EXCHANGE_KEY_NAME,
.VariableGuid = &gEfiGlobalVariableGuid,
},
[DB] = {
.Name = "DB",
.VarName = EFI_IMAGE_SECURITY_DATABASE,
.VarGuid = &gEfiImageSecurityDatabaseGuid,
.DisplayName = "DB",
.VariableName = EFI_IMAGE_SECURITY_DATABASE,
.VariableGuid = &gEfiImageSecurityDatabaseGuid,
},
[DBX] = {
.Name = "DBX",
.VarName = EFI_IMAGE_SECURITY_DATABASE1,
.VarGuid = &gEfiImageSecurityDatabaseGuid,
.DisplayName = "DBX",
.VariableName = EFI_IMAGE_SECURITY_DATABASE1,
.VariableGuid = &gEfiImageSecurityDatabaseGuid,
},
[DBT] = {
.Name = "DBT",
.VarName = EFI_IMAGE_SECURITY_DATABASE2,
.VarGuid = &gEfiImageSecurityDatabaseGuid,
.DisplayName = "DBT",
.VariableName = EFI_IMAGE_SECURITY_DATABASE2,
.VariableGuid = &gEfiImageSecurityDatabaseGuid,
},
[MOK] = {
.Name = "MOK",
.VarName = L"MokList",
.VarGuid = &gEfiShimLockGuid,
.DisplayName = "MOK",
.VariableName = L"MokList",
.VariableGuid = &gEfiShimLockGuid,
}
};

Expand Down Expand Up @@ -181,13 +181,13 @@ EFI_STATUS ParseList(
};
} else {
for (Type = 0; Type < MAX_TYPES; Type++) {
if (i + AsciiStrLen(KeyInfo[Type].Name) >= Installable->ListDataSize)
if (i + AsciiStrLen(KeyInfo[Type].DisplayName) >= Installable->ListDataSize)
continue;
if (AsciiStrnCmp(KeyInfo[Type].Name, &Installable->ListData[i], AsciiStrLen(KeyInfo[Type].Name)) != 0)
if (AsciiStrnCmp(KeyInfo[Type].DisplayName, &Installable->ListData[i], AsciiStrLen(KeyInfo[Type].DisplayName)) != 0)
continue;
if (!IsWhiteSpace(Installable->ListData[i + AsciiStrLen(KeyInfo[Type].Name)]))
if (!IsWhiteSpace(Installable->ListData[i + AsciiStrLen(KeyInfo[Type].DisplayName)]))
continue;
i += AsciiStrLen(KeyInfo[Type].Name);
i += AsciiStrLen(KeyInfo[Type].DisplayName);
while (IsWhiteSpace(Installable->ListData[i]) && i < Installable->ListDataSize)
i++;
if (Installable->List[Type].NumEntries < MOSBY_MAX_ENTRIES) {
Expand Down Expand Up @@ -223,6 +223,9 @@ EFI_STATUS EFIAPI efi_main(
IN EFI_SYSTEM_TABLE* SystemTable
)
{
// TODO: MOK may need different options
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;
EFI_STATUS Status, SetStatus;
INTN Argc, Type, Entry, Sel;
Expand Down Expand Up @@ -355,42 +358,44 @@ EFI_STATUS EFIAPI efi_main(
EFI_HANDLE Handle = NULL;
SafeFree(Installable.List[Type].Path[Entry]);
UnicodeSPrint(Title, ARRAY_SIZE(Title), L"Please select %a %s",
KeyInfo[Type].Name, (Type == DBX) ? L"binary" : L"certificate");
KeyInfo[Type].DisplayName, (Type == DBX) ? L"binary" : L"certificate");
Status = SimpleFileSelector(&Handle,
(CONST CHAR16 *[]){
L"",
Title,
NULL
}, L"\\", L".cer|.crt|.esl|.bin", &Installable.List[Type].Path[Entry]);
}, L"\\", L".cer|.crt|.esl|.bin|.auth", &Installable.List[Type].Path[Entry]);
RecallPrintRestore();
if (EFI_ERROR(Status))
continue;
if (!SimpleFileExistsByPath(gBaseImageHandle, Installable.List[Type].Path[Entry])) {
RecallPrint(L"No valid file selected for %a[%d] - Ignoring\n", KeyInfo[Type].Name, Entry);
RecallPrint(L"No valid file selected for %a[%d] - Ignoring\n", KeyInfo[Type].DisplayName, Entry);
continue;
}
}

Installable.List[Type].Esl[Entry] = LoadToEsl(Installable.List[Type].Path[Entry]);

if (Installable.List[Type].Esl[Entry] == NULL) {
RecallPrint(L"Failed to load %a[%d] - Aborting\n", KeyInfo[Type].Name, Entry);
Status = LoadToAuthVar(Installable.List[Type].Path[Entry], &Installable.List[Type].Variable[Entry]);
if (EFI_ERROR(Status)) {
RecallPrint(L"Failed to load %a[%d] - Aborting\n", KeyInfo[Type].DisplayName, Entry);
goto exit;
}
}
}

/* 6. Generate a keyless PK cert if none was specified */
if (Installable.List[PK].Esl[0] == NULL) {
if (Installable.List[PK].Variable[0].Data == NULL) {
RecallPrint(L"Generating PK certificate...\n");
SafeFree(Installable.List[PK].Path[0]);
Installable.List[PK].Path[0] = StrDup(L"AutoGenerated");
Cert = GenerateCredentials("Mosby Generated PK", NULL);
Installable.List[PK].Esl[0] = CertToEsl(Cert);
if (Installable.List[PK].Esl[0] == NULL) {
Cert = GenerateCredentials("Mosby Generated PK", &Key);
Status = CertToAuthVar(Cert, &Installable.List[PK].Variable[0]);
if (EFI_ERROR(Status)) {
SafeFree(Cert);
goto exit;
}
Status = SignToAuthVar(KeyInfo[PK].VariableName, KeyInfo[PK].VariableGuid,
Attributes, &Installable.List[PK].Variable[0], Cert, Key);
FreeCredentials(Cert, Key);
}

/* 7. Generate DB credentials if requested */
Expand All @@ -400,16 +405,17 @@ EFI_STATUS EFIAPI efi_main(
RecallPrint(L"Generating Secure Boot signing credentials...\n");
SafeFree(Installable.List[DB].Path[Entry]);
Installable.List[DB].Path[Entry] = StrDup(L"AutoGenerated");
Cert = GenerateCredentials("Secure Boot signing", &Key);;
Installable.List[DB].Esl[Entry] = CertToEsl(Cert);
if (Installable.List[DB].Esl[Entry] == NULL) {
Cert = GenerateCredentials("Secure Boot signing", &Key);
Status = CertToAuthVar(Cert, &Installable.List[DB].Variable[Entry]);
if (EFI_ERROR(Status)) {
SafeFree(Cert);
goto exit;
}
Status = SaveCredentials(Cert, Key, MOSBY_CRED_NAME);
if (EFI_ERROR(Status))
goto exit;
RecallPrint(L"Saved Secure Boot signing credentials as '%s'\n", MOSBY_CRED_NAME);
FreeCredentials(Cert, Key);
}

/* 8. Install the cert and DBX variables, making sure that we finish with the PK. */
Expand All @@ -418,12 +424,15 @@ EFI_STATUS EFIAPI efi_main(
Status = EFI_NOT_FOUND;
for (Type = MAX_TYPES - 1; Type >= 0; Type--) {
for (Entry = 0; Entry < Installable.List[Type].NumEntries; Entry++) {
if (Installable.List[Type].Esl[Entry] != NULL) {
RecallPrint(L"Installing %a[%d] (from %s)\n", KeyInfo[Type].Name, Entry, Installable.List[Type].Path[Entry]);
SetStatus = SetSecureBootVariable(KeyInfo[Type].VarName, KeyInfo[Type].VarGuid,
Installable.List[Type].Esl[Entry], (Entry != 0));
if (EFI_ERROR(SetStatus))
if (Installable.List[Type].Variable[Entry].Data != NULL) {
RecallPrint(L"Installing %a[%d] (from %s)\n", KeyInfo[Type].DisplayName, Entry, Installable.List[Type].Path[Entry]);
SetStatus = gRT->SetVariable(KeyInfo[Type].VariableName, KeyInfo[Type].VariableGuid,
Attributes | ((Entry != 0) ? EFI_VARIABLE_APPEND_WRITE : 0),
Installable.List[Type].Variable[Entry].Size, Installable.List[Type].Variable[Entry].Data);
if (EFI_ERROR(SetStatus)) {
Print(L"Failed to set Secure Boot variable: %r\n", SetStatus);
Status = SetStatus;
}
}
}
}
Expand All @@ -432,7 +441,7 @@ EFI_STATUS EFIAPI efi_main(
for (Type = 0; Type < MAX_TYPES; Type++)
for (Entry = 0; Entry < MOSBY_MAX_ENTRIES; Entry++) {
FreePool(Installable.List[Type].Path[Entry]);
FreePool(Installable.List[Type].Esl[Entry]);
FreePool(Installable.List[Type].Variable[Entry].Data);
}
FreePool(Installable.ListData);
FreePool(Argv);
Expand Down
8 changes: 7 additions & 1 deletion src/mosby.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <Guid/AuthenticatedVariableFormat.h>
#include <Uefi/UefiBaseType.h>
#include <UefiSecureBoot.h>
#include <Library/AuthVariableLib.h>
#include <Library/BaseLib.h>
#include <Library/BaseCryptLib.h>
#include <Library/BaseMemoryLib.h>
Expand Down Expand Up @@ -56,11 +57,16 @@ enum {
MAX_TYPES
};

typedef struct {
UINTN Size;
EFI_VARIABLE_AUTHENTICATION_2 *Data;
} AUTHENTICATED_VARIABLE;

/* Structure containing the list of "keys" for a specific type */
typedef struct {
UINTN NumEntries;
CHAR16 *Path[MOSBY_MAX_ENTRIES];
EFI_SIGNATURE_LIST *Esl[MOSBY_MAX_ENTRIES];
AUTHENTICATED_VARIABLE Variable[MOSBY_MAX_ENTRIES];
} INSTALLABLE_LIST;

/* Structure containing the collection of all the lists */
Expand Down
Loading

0 comments on commit dd9d43d

Please sign in to comment.