OpenCorePkg/Library/OcHashServicesLib/OcHashServicesLib.c

231 lines
5.7 KiB
C

/**
* Hash service fix for AMI EFIs with broken SHA implementations.
*
* Forcibly reinstalls EFI_HASH_PROTOCOL with working MD5, SHA-1,
* SHA-256 implementations.
*
* Author: Joel Hoener <athre0z@zyantific.com>
*/
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/OcMiscLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Protocol/Hash.h>
#include <Protocol/ServiceBinding.h>
#include "OcHashServicesLibInternal.h"
STATIC EFI_SERVICE_BINDING_PROTOCOL mHashBindingProto = {
&HSCreateChild,
&HSDestroyChild
};
STATIC
EFI_STATUS
EFIAPI
HSGetHashSize (
IN CONST EFI_HASH_PROTOCOL *This,
IN CONST EFI_GUID *HashAlgorithm,
OUT UINTN *HashSize
)
{
if (!HashAlgorithm || !HashSize) {
return EFI_INVALID_PARAMETER;
}
if (CompareGuid (&gEfiHashAlgorithmMD5Guid, HashAlgorithm)) {
*HashSize = sizeof (EFI_MD5_HASH);
return EFI_SUCCESS;
} else if (CompareGuid (&gEfiHashAlgorithmSha1Guid, HashAlgorithm)) {
*HashSize = sizeof (EFI_SHA1_HASH);
return EFI_SUCCESS;
} else if (CompareGuid (&gEfiHashAlgorithmSha256Guid, HashAlgorithm)) {
*HashSize = sizeof (EFI_SHA256_HASH);
return EFI_SUCCESS;
}
return EFI_UNSUPPORTED;
}
STATIC
EFI_STATUS
EFIAPI
HSHash (
IN CONST EFI_HASH_PROTOCOL *This,
IN CONST EFI_GUID *HashAlgorithm,
IN BOOLEAN Extend,
IN CONST UINT8 *Message,
IN UINT64 MessageSize,
IN OUT EFI_HASH_OUTPUT *Hash
)
{
HS_PRIVATE_DATA *PrivateData;
HS_CONTEXT_DATA CtxCopy;
if (!This || !HashAlgorithm || !Message || !Hash || !MessageSize || (MessageSize > MAX_UINTN)) {
return EFI_INVALID_PARAMETER;
}
PrivateData = HS_PRIVATE_FROM_PROTO (This);
if (CompareGuid (&gEfiHashAlgorithmMD5Guid, HashAlgorithm)) {
if (!Extend) {
Md5Init (&PrivateData->Ctx.Md5);
}
Md5Update (&PrivateData->Ctx.Md5, Message, (UINTN)MessageSize);
CopyMem (&CtxCopy, &PrivateData->Ctx, sizeof (PrivateData->Ctx));
Md5Final (&CtxCopy.Md5, *Hash->Md5Hash);
return EFI_SUCCESS;
} else if (CompareGuid (&gEfiHashAlgorithmSha1Guid, HashAlgorithm)) {
if (!Extend) {
Sha1Init (&PrivateData->Ctx.Sha1);
}
Sha1Update (&PrivateData->Ctx.Sha1, Message, (UINTN)MessageSize);
CopyMem (&CtxCopy, &PrivateData->Ctx, sizeof (PrivateData->Ctx));
Sha1Final (&CtxCopy.Sha1, *Hash->Sha1Hash);
return EFI_SUCCESS;
} else if (CompareGuid (&gEfiHashAlgorithmSha256Guid, HashAlgorithm)) {
if (!Extend) {
Sha256Init (&PrivateData->Ctx.Sha256);
}
Sha256Update (&PrivateData->Ctx.Sha256, Message, (UINTN)MessageSize);
CopyMem (&CtxCopy, &PrivateData->Ctx, sizeof (PrivateData->Ctx));
Sha256Final (&CtxCopy.Sha256, *Hash->Sha256Hash);
return EFI_SUCCESS;
}
return EFI_UNSUPPORTED;
}
STATIC
EFI_STATUS
EFIAPI
HSCreateChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN OUT EFI_HANDLE *ChildHandle
)
{
HS_PRIVATE_DATA *PrivateData;
EFI_STATUS Status;
PrivateData = AllocateZeroPool (sizeof (*PrivateData));
if (!PrivateData) {
return EFI_OUT_OF_RESOURCES;
}
PrivateData->Signature = HS_PRIVATE_SIGNATURE;
PrivateData->Proto.GetHashSize = HSGetHashSize;
PrivateData->Proto.Hash = HSHash;
Status = gBS->InstallProtocolInterface (
ChildHandle,
&gEfiHashProtocolGuid,
EFI_NATIVE_INTERFACE,
&PrivateData->Proto
);
if (EFI_ERROR (Status)) {
FreePool (PrivateData);
}
return Status;
}
STATIC
EFI_STATUS
EFIAPI
HSDestroyChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE ChildHandle
)
{
EFI_HASH_PROTOCOL *HashProto;
EFI_STATUS Status;
if (!This || !ChildHandle) {
return EFI_INVALID_PARAMETER;
}
Status = gBS->HandleProtocol (
ChildHandle,
&gEfiHashProtocolGuid,
(VOID **)&HashProto
);
if (EFI_ERROR (Status)) {
return Status;
}
Status = gBS->UninstallProtocolInterface (
ChildHandle,
&gEfiHashProtocolGuid,
HashProto
);
if (EFI_ERROR (Status)) {
return Status;
}
FreePool (HS_PRIVATE_FROM_PROTO (HashProto));
return EFI_SUCCESS;
}
/**
Install and initialise EFI Service Binding protocol.
@param[in] Reinstall Replace any installed protocol.
@returns Installed protocol.
@retval NULL There was an error installing the protocol.
**/
EFI_SERVICE_BINDING_PROTOCOL *
OcHashServicesInstallProtocol (
IN BOOLEAN Reinstall
)
{
EFI_STATUS Status;
EFI_HANDLE NewHandle = NULL;
EFI_SERVICE_BINDING_PROTOCOL *OriginalProto = NULL;
if (Reinstall) {
//
// Uninstall all the existing protocol instances (which are not to be trusted).
//
Status = OcUninstallAllProtocolInstances (&gEfiHashServiceBindingProtocolGuid);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "OCHS: Uninstall failed - %r\n", Status));
return NULL;
}
} else {
Status = gBS->LocateProtocol (
&gEfiHashServiceBindingProtocolGuid,
NULL,
(VOID **)&OriginalProto
);
if (!EFI_ERROR (Status)) {
return OriginalProto;
}
}
//
// Install our own protocol binding
//
Status = gBS->InstallMultipleProtocolInterfaces (
&NewHandle,
&gEfiHashServiceBindingProtocolGuid,
&mHashBindingProto,
NULL
);
if (EFI_ERROR (Status)) {
return NULL;
}
return &mHashBindingProto;
}