/** * 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 */ #include #include #include #include #include #include #include #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; }