mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2025-12-08 19:25:01 +00:00
231 lines
5.7 KiB
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;
|
|
}
|