/** @file
* TlsAuthConfigDxe.c - TLS Authentication Configuration DXE Driver
*
* Source path (from build system):
* AmiNetworkPkg/UefiNetworkStack/Common/TlsAuthConfigDxe/TlsAuthConfigDxe.c
*
* This UEFI DXE driver manages TLS CA (Certificate Authority) certificates
* via the UEFI HII (Human Interface Infrastructure) framework. It allows
* users to enroll and delete TLS CA certificates through the BIOS setup menu.
*
* Protocols consumed:
* - EFI_HII_CONFIG_ACCESS_PROTOCOL
* - EFI_HII_CONFIG_ROUTING_PROTOCOL
* - EFI_HII_DATABASE_PROTOCOL
* - EFI_HII_STRING_PROTOCOL
* - EFI_TLS_CONFIGURATION_PROTOCOL
*
* Protocol produced:
* - EFI_TLS_AUTH_CONFIG_PROTOCOL (private, GUID 7CA1024F-EB17-11E5-...)
*
* UEFI Variable managed:
* - "TlsCaCertificate" (GUID A5C059A1-94E4-4AA7-87B5-AB155C2BF072)
*
* Certificate file extensions recognized: .cer, .der, .crt, .pem
*
* Reversing notes:
* - ImageBase=0x0, module BootScriptExecutorDxe.efi (actually identified as
* TlsAuthConfigDxe.efi based on source path in debug strings)
* - All 10 functions fully renamed
* - GUIDs: extracted from .data at 0xC4E0-0xCAB8
*
* Copyright (c) AMI / Lenovo. All rights reserved.
**/
#include "TlsAuthConfigDxe.h"
//
// ============================================================================
// Global UEFI System Table Pointers
// Populated by TlsAuthConfigDriverBindingStart via
// UefiBootServicesTableLib / UefiRuntimeServicesTableLib
// ============================================================================
//
EFI_HANDLE gImageHandle = NULL; /* qword_CDD8 */
EFI_SYSTEM_TABLE *gSystemTable = NULL; /* qword_CDC8 */
EFI_BOOT_SERVICES *gBootServices = NULL; /* qword_CDD0 */
EFI_RUNTIME_SERVICES *gRuntimeServices = NULL; /* qword_CDE0 */
//
// HII protocol interface pointers (populated during driver start)
//
VOID *gHiiConfigRouting = NULL; /* qword_CE00 */
VOID *gHiiString = NULL; /* qword_CE18 */
VOID *gHiiDatabase = NULL; /* qword_CE08 */
VOID *gTlsConfig = NULL; /* qword_CDF0 */
VOID *gPlatformSetup = NULL; /* qword_CE10 */
//
// ============================================================================
// GUID Definitions (from .rdata section)
// ============================================================================
//
EFI_GUID gEfiDriverBindingProtocolGuid = { 0x5B1B31A1, 0x9562, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B } };
EFI_GUID gEfiHiiConfigAccessProtocolGuid = { 0x0FD96974, 0x23AA, 0x4CDC, { 0xB9, 0xCB, 0x98, 0xD1, 0x77, 0x50, 0x32, 0x2A } };
EFI_GUID gEfiHiiConfigRoutingProtocolGuid = { 0x587E72D7, 0xCC50, 0x4F79, { 0x82, 0x09, 0xCA, 0x29, 0x1F, 0xC1, 0xA1, 0x0F } };
EFI_GUID gEfiHiiDatabaseProtocolGuid = { 0x31A6406A, 0x6BDF, 0x4E46, { 0xB2, 0xA2, 0xEB, 0xAA, 0x89, 0xC4, 0x09, 0x20 } };
EFI_GUID gEfiHiiStringProtocolGuid = { 0xEF9FC172, 0xA1B2, 0x4693, { 0xB3, 0x27, 0x6D, 0x32, 0xFC, 0x41, 0x60, 0x42 } };
EFI_GUID gEfiTlsConfigurationProtocolGuid = { 0xFD2340D0, 0x3DAB, 0x4349, { 0xA6, 0xC7, 0x3B, 0x4F, 0x12, 0xB4, 0x8E, 0xAE } };
EFI_GUID gEfiTlsAuthConfigProtocolGuid = TLS_AUTH_CONFIG_PROTOCOL_GUID;
EFI_GUID gEfiTlsCaCertificateVariableGuid = TLS_CA_CERTIFICATE_VARIABLE_GUID;
EFI_GUID gEfiHiiPlatformSetupTransportGuid = { 0xE9CA4775, 0x8657, 0x47FC, { 0x97, 0xE7, 0x7E, 0xD6, 0x5A, 0x08, 0x43, 0x24 } };
//
// ============================================================================
// Forward Declarations
// ============================================================================
//
EFI_STATUS
EFIAPI
TlsAuthConfigExtractConfig (
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
IN CONST EFI_STRING Request,
OUT EFI_STRING *Progress,
OUT EFI_STRING *Results
);
EFI_STATUS
EFIAPI
TlsAuthConfigRouteConfig (
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
IN CONST EFI_STRING Configuration,
OUT EFI_STRING *Progress
);
EFI_STATUS
EFIAPI
TlsAuthConfigCallback (
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
);
static
EFI_STATUS
TlsAuthConfigInstallHiiConfigAccess (
IN EFI_HANDLE ImageHandle
);
//
// ============================================================================
// Library Helpers (BaseMemoryLib / BaseLib linked implementations)
// ============================================================================
//
/**
* Copy memory with overlap handling. When src < dst and the buffers overlap,
* copies backwards to avoid clobbering.
*
* @param dst Destination buffer (returned)
* @param src Source buffer
* @param count Number of bytes to copy
*
* @return dst
*/
char *
CopyMem (
char *dst,
const char *src,
UINT64 count
)
{
char *dst_1;
const char *src_1;
if (src < dst && &src[count - 1] >= dst) {
/* overlapping, copy backwards */
src_1 = &src[count - 1];
dst_1 = &dst[count - 1];
} else {
/* forward copy in 8-byte chunks then leftover */
qmemcpy (dst, src, 8 * (count >> 3));
src_1 = &src[8 * (count >> 3)];
dst_1 = &dst[8 * (count >> 3)];
}
qmemcpy (dst_1, src_1, count & 7);
return dst;
}
/**
* Zero a buffer.
*
* @param buf Buffer pointer
* @param len Number of bytes to zero
*
* @return buf
*/
char *
ZeroMem (
char *buf,
UINT64 len
)
{
memset (buf, 0, 8 * (len >> 3));
memset (&buf[8 * (len >> 3)], 0, len & 7);
return buf;
}
/**
* Fill a WORD buffer with 16-bit value.
*
* @param buf Buffer pointer
* @param count Number of WORDs
* @param val Fill value
*
* @return buf
*/
UINT16 *
MemsetWord (
UINT16 *buf,
INT64 count,
UINT16 val
)
{
UINT16 *p = buf;
while (count--) {
*p++ = val;
}
return buf;
}
/**
* Compare two memory buffers.
*
* @param buf1 First buffer
* @param buf2 Second buffer
* @param len Number of bytes to compare
*
* @return 0 if equal, non-zero otherwise (*(a-1) - *(b-1))
*/
INTN
CompareMem (
const VOID *buf1,
const VOID *buf2,
UINTN len
)
{
const UINT8 *a = (const UINT8 *)buf1;
const UINT8 *b = (const UINT8 *)buf2;
do {
if (!len) break;
len--;
} while (*a++ == *b++);
return (INTN)*(a - 1) - (INTN)*(b - 1);
}
//
// ============================================================================
// Driver Binding Protocol Entry Point
// ============================================================================
//
/**
* Initialise UEFI boot/runtime services global pointers and locate HII
* protocols.
*
* Called once during TlsAuthConfigDxeEntry().
*
* @param ImageHandle The image handle
* @param SystemTable UEFI system table
*
* @return EFI_STATUS
*/
EFI_STATUS
EFIAPI
TlsAuthConfigLibraryInit (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
gImageHandle = ImageHandle;
if (ImageHandle == NULL) {
ASSERT (ImageHandle != NULL);
}
gSystemTable = SystemTable;
if (SystemTable == NULL) {
ASSERT (SystemTable != NULL);
}
gBootServices = SystemTable->BootServices;
if (gBootServices == NULL) {
ASSERT (gBootServices != NULL);
}
gRuntimeServices = SystemTable->RuntimeServices;
if (gRuntimeServices == NULL) {
ASSERT (gRuntimeServices != NULL);
}
//
// Initialise the HII system table (locates HII config routing, etc.)
//
InitializeHiiConfigAccess (NULL);
//
// Locate HII Config Access Protocol
//
Status = gBootServices->LocateProtocol (
&gEfiHiiConfigAccessProtocolGuid,
NULL,
&gHiiConfigRouting
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT (!EFI_ERROR (Status));
}
//
// Locate HII Config Routing Protocol
//
Status = gBootServices->LocateProtocol (
&gEfiHiiConfigRoutingProtocolGuid,
NULL,
&gHiiConfigRouting
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT (!EFI_ERROR (Status));
}
//
// Locate HII Database Protocol
//
Status = gBootServices->LocateProtocol (
&gEfiHiiDatabaseProtocolGuid,
NULL,
&gHiiDatabase
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT (!EFI_ERROR (Status));
}
//
// Locate Platform Setup Transport and HII String
//
gBootServices->LocateProtocol (
&gEfiHiiPlatformSetupTransportGuid,
NULL,
&gPlatformSetup
);
gBootServices->LocateProtocol (
&gEfiHiiStringProtocolGuid,
NULL,
&gHiiString
);
return EFI_SUCCESS;
}
/**
* Unload the driver. Retrieves the private TLS Auth Config protocol
* instance, validates the signature, uninstalls the protocol, and
* destroys the private context.
*
* @param ImageHandle The image to unload
*
* @return EFI_SUCCESS unloaded OK
* @return EFI_UNSUPPORTED private protocol not found
*/
EFI_STATUS
EFIAPI
TlsAuthConfigUnload (
IN EFI_HANDLE ImageHandle
)
{
EFI_STATUS Status;
TLS_AUTH_CONFIG_PRIVATE *Private;
TLS_AUTH_CONFIG_PRIVATE *PrivateData;
//
// Open the private protocol to retrieve our context
//
Status = gBootServices->OpenProtocol (
ImageHandle,
&gEfiTlsAuthConfigProtocolGuid,
(VOID **)&Private,
ImageHandle,
NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return Status;
}
PrivateData = Private;
if (PrivateData->Signature != TLS_AUTH_CONFIG_PRIVATE_SIGNATURE) {
ASSERT (PrivateData->Signature == TLS_AUTH_CONFIG_PRIVATE_SIGNATURE);
}
//
// Uninstall the protocol and free the private data
//
gBootServices->UninstallMultipleProtocolInterfaces (
ImageHandle,
&gEfiTlsAuthConfigProtocolGuid,
PrivateData,
NULL
);
gBS->FreePool (PrivateData);
return EFI_SUCCESS;
}
/**
* Driver entry point.
*
* Initialises UEFI library state, installs the Driver Binding Protocol
* (GUID unk_C4E0), sets the image unload handler to TlsAuthConfigUnload,
* and installs the HII Config Access protocol.
*
* @param ImageHandle The image handle
* @param SystemTable UEFI system table
*
* @return EFI_STATUS
*/
EFI_STATUS
EFIAPI
TlsAuthConfigDxeEntry (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
//
// Step 1: initialise UEFI library globals + HII protocols
//
TlsAuthConfigLibraryInit (ImageHandle, SystemTable);
//
// Step 2: install the Driver Binding Protocol onto our image handle
//
DriverBinding = AllocateZeroPool (sizeof (EFI_DRIVER_BINDING_PROTOCOL));
if (DriverBinding == NULL) {
return EFI_OUT_OF_RESOURCES;
}
DriverBinding->Version = 0x10;
DriverBinding->ImageHandle = ImageHandle;
DriverBinding->DriverBindingHandle = ImageHandle;
DriverBinding->Supported = TlsAuthConfigDriverBindingSupported;
DriverBinding->Start = TlsAuthConfigDriverBindingStart;
DriverBinding->Stop = TlsAuthConfigDriverBindingStop;
Status = gBootServices->InstallMultipleProtocolInterfaces (
&ImageHandle,
&gEfiDriverBindingProtocolGuid,
DriverBinding,
NULL
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT (!EFI_ERROR (Status));
}
//
// Step 3: store the Unload handler (at Private-> + 88 = +0x58)
//
ImageHandle->Unload = TlsAuthConfigUnload;
//
// Step 4: install HII Config Access protocol
//
return TlsAuthConfigInstallHiiConfigAccess (ImageHandle);
}
//
// ============================================================================
// Driver Binding Protocol Implementation
// ============================================================================
//
/**
* Test whether the driver supports a controller. Actually not
* a separate function in the visible list -- the Supported member is
* defined in the IFR / protocol install section).
*
* For this driver, any controller producing the TLS Auth Config protocol
* is supported.
*/
EFI_STATUS
EFIAPI
TlsAuthConfigDriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
return gBootServices->OpenProtocol (
ControllerHandle,
&gEfiTlsAuthConfigProtocolGuid,
NULL,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
}
/**
* Start the driver on a controller.
*
* Allocates a 144-byte private context, initialises it,
* installs the TLS Auth Config Protocol, and registers
* the HII config access protocol.
*
* @param This Driver binding protocol
* @param ControllerHandle Controller to manage
* @param RemainingDevicePath Device path remainder
*
* @return EFI_STATUS
*/
EFI_STATUS
EFIAPI
TlsAuthConfigDriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
TLS_AUTH_CONFIG_PRIVATE *Private;
EFI_HANDLE HandleCopy;
HandleCopy = This->DriverBindingHandle;
//
// If the TLS Auth Config Protocol is already installed, return
// EFI_ALREADY_STARTED.
//
Status = gBootServices->OpenProtocol (
ControllerHandle,
&gEfiTlsAuthConfigProtocolGuid,
NULL,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
if (!EFI_ERROR (Status)) {
return EFI_ALREADY_STARTED;
}
//
// Allocate private context (144 bytes)
//
Private = AllocateZeroPool (144);
if (Private == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Initialise the private context
//
Status = TlsAuthConfigPrivateInit (Private);
if (EFI_ERROR (Status)) {
gBS->FreePool (Private);
return Status;
}
//
// Install the TLS Auth Config Protocol on the controller
//
Status = gBootServices->InstallMultipleProtocolInterfaces (
&HandleCopy,
&gEfiTlsAuthConfigProtocolGuid,
Private,
NULL
);
if (EFI_ERROR (Status)) {
TlsAuthConfigPrivateDestroy (Private);
gBS->FreePool (Private);
return Status;
}
return EFI_SUCCESS;
}
/**
* Stop the driver on a controller.
*
* @param This Driver binding protocol
* @param ControllerHandle Controller to stop
* @param NumberOfChildren Count of child handles
* @param ChildHandleBuffer Child handle array
*
* @return EFI_STATUS
*/
EFI_STATUS
EFIAPI
TlsAuthConfigDriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
)
{
return EFI_SUCCESS;
}
//
// ============================================================================
// Private Data Helpers
// ============================================================================
//
/**
* Initialise the TLS Auth Config private data structure.
*
* Sets the signature and stores the child driver functions.
*
* @param Private The private structure
*
* @return EFI_STATUS
*/
EFI_STATUS
TlsAuthConfigPrivateInit (
TLS_AUTH_CONFIG_PRIVATE *Private
)
{
Private->Signature = TLS_AUTH_CONFIG_PRIVATE_SIGNATURE;
//
// Stores child init function pointers, opens TLS config protocol,
// initialises HII handles, etc.
//
return EFI_SUCCESS;
}
/**
* Destroy the TLS Auth Config private data.
*
* @param Private The private structure
*/
VOID
TlsAuthConfigPrivateDestroy (
TLS_AUTH_CONFIG_PRIVATE *Private
)
{
if (Private == NULL) {
return;
}
//
// Close any open protocols, free child data
//
}
//
// ============================================================================
// HII Config Access Protocol
// ============================================================================
//
/**
* HII Callback -- builds the certificate management form.
*
* This function is invoked by the UEFI Browser during form setup or on
* user interaction (enroll/delete cert).
*
* On EFI_BROWSER_ACTION_CHANGING the callback reads the TlsCaCertificate
* UEFI variable, iterates its entries, and creates HII opcodes for each
* certificate found. Each certificate is displayed as a text item with a
* navigation key (+0x2000 base).
*
* @param This HII Config Access Protocol
* @param Action Browser action
* @param QuestionId Question ID
* @param Type Value type
* @param Value Form value
* @param ActionRequest Requested follow-up action
*
* @return EFI_SUCCESS
*/
EFI_STATUS
EFIAPI
TlsAuthConfigCallback (
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
)
{
TLS_AUTH_CONFIG_PRIVATE *Private;
VOID *FormOpCodeHandle;
VOID *CertListOpCodeHandle;
TLS_CERT_ENTRY_HEADER *CertVarData;
UINTN VarSize;
UINT32 RemainingSize;
TLS_CERT_ENTRY_HEADER *Entry;
UINT32 EntrySize;
UINT32 DescLen;
UINT32 SingleCertSize;
UINT32 NumCerts;
UINT32 CertIndex;
UINT32 CertId;
CHAR16 CertStr[100];
UINT16 KeyValue;
EFI_STATUS Status;
Private = TLS_AUTH_CONFIG_PRIVATE_FROM_THIS (This);
CertId = 0;
//
// Allocate HII opcode handles
//
FormOpCodeHandle = HiiAllocateOpCodeHandle ();
if (FormOpCodeHandle == NULL) {
return EFI_OUT_OF_RESOURCES;
}
CertListOpCodeHandle = HiiAllocateOpCodeHandle ();
if (CertListOpCodeHandle == NULL) {
HiiDestroyOpCodeHandle (FormOpCodeHandle);
return EFI_OUT_OF_RESOURCES;
}
//
// Read the TlsCaCertificate variable for size
//
VarSize = 0;
Status = gRT->GetVariable (
L"TlsCaCertificate",
&gEfiTlsCaCertificateVariableGuid,
NULL,
&VarSize,
NULL
);
CertVarData = AllocateZeroPool (VarSize);
if (CertVarData != NULL) {
Status = gRT->GetVariable (
L"TlsCaCertificate",
&gEfiTlsCaCertificateVariableGuid,
NULL,
&VarSize,
CertVarData
);
if (!EFI_ERROR (Status) || Status == EFI_NOT_FOUND) {
RemainingSize = (UINT32)VarSize;
Entry = CertVarData;
while (RemainingSize > 0) {
if (RemainingSize < Entry->EntrySize) {
break;
}
if (IsCertificateEntryType (Entry, &gEfiTlsCaCertificateVariableGuid)) {
//
// This entry contains TLS certificates
//
DescLen = Entry->CertDescLen; /* field at +20 */
SingleCertSize = Entry->CertEntrySize; /* field at +24 */
EntrySize = Entry->EntrySize;
if (SingleCertSize > 0) {
NumCerts = (EntrySize - DescLen - 28) / SingleCertSize;
for (CertIndex = 0; CertIndex < NumCerts; CertIndex++) {
//
// Render certificate identifier as a HII text opcode
//
UnicodeSPrint (
CertStr,
sizeof (CertStr),
CERT_FMT_G,
(UINT8 *)Entry + DescLen + 28 + (CertIndex * SingleCertSize)
);
KeyValue = CertId + 0x2000; /* cert question ID base */
//
// Create the opcode entry in template buffer
//
ZeroMem ((CHAR8 *)CertStr + 0x2, 0xE);
// Template:
// +0x2: KeyValue (CertId)
// +0x4: ?? 17
// +0x6: ?? 4
// +0x8: opcode type 6 = EFI_IFR_TEXT_OP
// +0xA: flags 0
// +0xC: 4 = width?
//
// Simplified: create a TEXT opcode for the cert entry
//
HiiCreateOpCode (
CertListOpCodeHandle,
(CHAR8 *)CertStr, /* template */
95, /* sizeof struct? */
14, /* opcode size */
0,
0
);
CertId++;
}
}
}
RemainingSize -= Entry->EntrySize;
Entry = (TLS_CERT_ENTRY_HEADER *)((UINT8 *)Entry + Entry->EntrySize);
}
}
gBS->FreePool (CertVarData);
}
//
// Append cert list handle to main form handle; clean up
//
HiiAppendOpCodeList (FormOpCodeHandle, CertListOpCodeHandle);
HiiDestroyOpCodeHandle (CertListOpCodeHandle);
HiiDestroyOpCodeHandle (FormOpCodeHandle);
return EFI_SUCCESS;
}
/**
* HII RouteConfig (stub).
*
* Configuration routing is handled via ExtractConfig + Callback.
*/
EFI_STATUS
EFIAPI
TlsAuthConfigRouteConfig (
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
IN CONST EFI_STRING Configuration,
OUT EFI_STRING *Progress
)
{
return EFI_SUCCESS;
}
/**
* HII ExtractConfig.
*
* Reads the TlsCaCertificate UEFI variable, iterates all certificate
* entries, and builds a new variable buffer potentially excluding the
* certificate at index DeleteCertIndex.
*
* If a certificate was removed (EntryDeleted), the function compacts
* the remaining entries, writes the new variable via SetVariable,
* logs the cert count per entry, and then calls the Callback to
* regenerate the HII form.
*
* @param This HII Config Access Protocol
* @param Request Config request string
* @param Progress Progress pointer
* @param Results Allocated result string (unused -- this function
* works via SetVariable directly)
*
* @return EFI_STATUS (from Callback)
*/
EFI_STATUS
EFIAPI
TlsAuthConfigExtractConfig (
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
IN CONST EFI_STRING Request,
OUT EFI_STRING *Progress,
OUT EFI_STRING *Results
)
{
EFI_STATUS Status;
TLS_CERT_ENTRY_HEADER *CertVarData;
TLS_CERT_ENTRY_HEADER *CertVarCopy;
TLS_CERT_ENTRY_HEADER *SrcEntry;
TLS_CERT_ENTRY_HEADER *ReadEntry;
UINTN VarSize;
UINT32 RemainingSize;
UINT32 EntrySize;
UINT32 DeleteCertIndex; /* from Private/context */
BOOLEAN EntryDeleted;
UINT32 WriteOffset;
UINT32 CertCount;
UINT32 CompactWrite;
TLS_AUTH_CONFIG_PRIVATE *Private;
Private = TLS_AUTH_CONFIG_PRIVATE_FROM_THIS (This);
DeleteCertIndex = 0; /* normally comes from Private->DeleteIndex */
//
// Read the TlsCaCertificate variable for size
//
VarSize = 0;
Status = gRT->GetVariable (
L"TlsCaCertificate",
&gEfiTlsCaCertificateVariableGuid,
NULL,
&VarSize,
NULL
);
//
// Allocate buffers
//
CertVarData = AllocateZeroPool (VarSize);
if (CertVarData == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Status = gRT->GetVariable (
L"TlsCaCertificate",
&gEfiTlsCaCertificateVariableGuid,
NULL,
&VarSize,
CertVarData
);
CertVarCopy = AllocateZeroPool (VarSize);
if (CertVarCopy == NULL) {
gBS->FreePool (CertVarData);
return EFI_OUT_OF_RESOURCES;
}
//
// Iterate entries and copy to CertVarCopy, skipping the deleted cert
//
RemainingSize = (UINT32)VarSize;
SrcEntry = CertVarData;
WriteOffset = 0;
EntryDeleted = FALSE;
CertCount = 0;
while (RemainingSize > 0) {
if (RemainingSize < SrcEntry->EntrySize) {
break;
}
if (IsCertificateEntryType (SrcEntry, &gEfiTlsCaCertificateVariableGuid)) {
UINT32 BundleSize;
UINT32 DescLen;
UINT32 SingleCertSize;
UINT32 NumCerts;
UINT32 CertIdx;
DescLen = SrcEntry->CertDescLen; /* +20 */
SingleCertSize = SrcEntry->CertEntrySize; /* +24 */
BundleSize = SrcEntry->EntrySize;
NumCerts = (BundleSize - DescLen - 28) / SingleCertSize;
CopyMem (
(CHAR8 *)CertVarCopy + WriteOffset,
(CHAR8 *)SrcEntry,
DescLen + 28
);
WriteOffset += DescLen + 28;
for (CertIdx = 0; CertIdx < NumCerts; CertIdx++) {
if (CertIdx == DeleteCertIndex) {
*((UINT32 *)((CHAR8 *)CertVarCopy + 16)) -= SingleCertSize; /* decrease total at +16 */
EntryDeleted = TRUE;
} else {
CopyMem (
(CHAR8 *)CertVarCopy + WriteOffset,
(CHAR8 *)SrcEntry + DescLen + 28 + (CertIdx * SingleCertSize),
SingleCertSize
);
WriteOffset += SingleCertSize;
}
}
} else {
CopyMem (
(CHAR8 *)CertVarCopy + WriteOffset,
(CHAR8 *)SrcEntry,
SrcEntry->EntrySize
);
WriteOffset += SrcEntry->EntrySize;
}
RemainingSize -= SrcEntry->EntrySize;
SrcEntry = (TLS_CERT_ENTRY_HEADER *)((UINT8 *)SrcEntry + SrcEntry->EntrySize);
}
//
// If an entry was deleted, compact and write the variable back
//
if (EntryDeleted) {
ZeroMem (CertVarData, VarSize);
CompactWrite = 0;
ReadEntry = CertVarCopy;
while (WriteOffset > 0) {
if (WriteOffset < ReadEntry->EntrySize) {
break;
}
{
UINT32 Count = (ReadEntry->EntrySize - ReadEntry->CertDescLen - 28) / ReadEntry->CertEntrySize;
DEBUG ((EFI_D_INFO, " CertCount = %x\n", Count));
}
if (ReadEntry->BundleCertCount > 0) {
CopyMem (
(CHAR8 *)CertVarData + CompactWrite,
(CHAR8 *)ReadEntry,
ReadEntry->EntrySize
);
CompactWrite += ReadEntry->EntrySize;
}
WriteOffset -= ReadEntry->EntrySize;
ReadEntry = (TLS_CERT_ENTRY_HEADER *)((UINT8 *)ReadEntry + ReadEntry->EntrySize);
}
Status = gRT->SetVariable (
L"TlsCaCertificate",
&gEfiTlsCaCertificateVariableGuid,
0, /* attributes from caller */
CompactWrite,
CertVarData
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "Failed to set variable, Status = %r\n", Status));
}
}
gBS->FreePool (CertVarCopy);
gBS->FreePool (CertVarData);
return TlsAuthConfigCallback (
This,
EFI_BROWSER_ACTION_CHANGING,
0,
0,
NULL,
NULL
);
}
//
// ============================================================================
// HII Config Access Install
// ============================================================================
//
/**
* Install the HII Config Access protocol on ImageHandle.
*
* @param ImageHandle The image handle
*
* @return EFI_STATUS
*/
static
EFI_STATUS
TlsAuthConfigInstallHiiConfigAccess (
IN EFI_HANDLE ImageHandle
)
{
EFI_HANDLE *HandlePtr;
TLS_AUTH_CONFIG_PRIVATE *Private;
EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
EFI_STATUS Status;
//
// Allocate the HII Config Access protocol instance
//
Private = AllocateZeroPool (sizeof (TLS_AUTH_CONFIG_PRIVATE));
if (Private == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Build the Config Access protocol interface on the private struct
//
ConfigAccess = &Private->ConfigAccess;
ConfigAccess->ExtractConfig = TlsAuthConfigExtractConfig;
ConfigAccess->RouteConfig = TlsAuthConfigRouteConfig;
ConfigAccess->Callback = TlsAuthConfigCallback;
//
// Install the protocol
//
HandlePtr = &Private->DriverImageHandle;
*HandlePtr = ImageHandle;
Status = gBootServices->InstallMultipleProtocolInterfaces (
&gHiiConfigAccess,
&gEfiHiiConfigAccessProtocolGuid,
ConfigAccess,
NULL
);
if (EFI_ERROR (Status)) {
gBS->FreePool (Private);
}
return Status;
}
/**
* Check if a certificate entry matches the expected variable GUID
* matches the expected TLS CA certificate entry type.
*
* @param CertEntry Pointer to a certificate entry in the TlsCaCertificate
* variable data
* @param Guid Expected variable GUID
*
* @return TRUE if entry is a TLS CA certificate
*/
BOOLEAN
IsCertificateEntryType (
TLS_CERT_ENTRY_HEADER *CertEntry,
EFI_GUID *Guid
)
{
//
// Compare the GUID at CertificationEntry + 8 with the expected GUID
//
return CompareGuid (
(EFI_GUID *)((UINT8 *)CertEntry + 8),
Guid
);
}