mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2025-12-08 19:25:01 +00:00
554 lines
16 KiB
C
554 lines
16 KiB
C
/** @file
|
|
Copyright (C) 2019, Download-Fritz. All rights reserved.
|
|
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
**/
|
|
|
|
#include <Uefi.h>
|
|
|
|
#include <Guid/AppleVariable.h>
|
|
|
|
#include <Protocol/AppleImg4Verification.h>
|
|
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/OcAppleKeysLib.h>
|
|
#include <Library/OcCryptoLib.h>
|
|
#include <Library/OcAppleImg4Lib.h>
|
|
#include <Library/OcMiscLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Library/UefiRuntimeServicesTableLib.h>
|
|
|
|
#include "libDER/oids.h"
|
|
#include "libDERImg4/libDERImg4.h"
|
|
#include "libDERImg4/Img4oids.h"
|
|
|
|
GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 *DERImg4RootCertificate = gAppleX86SecureBootRootCaCert;
|
|
GLOBAL_REMOVE_IF_UNREFERENCED const UINTN *DERImg4RootCertificateSize = &gAppleX86SecureBootRootCaCertSize;
|
|
|
|
typedef struct OC_SB_MODEL_DESC_ {
|
|
CONST CHAR8 *HardwareModel;
|
|
UINT32 BoardId;
|
|
} OC_SB_MODEL_DESC;
|
|
|
|
STATIC CHAR8 mCryptoDigestMethod[16] = "sha2-384";
|
|
STATIC DERImg4Environment mEnvInfo;
|
|
///
|
|
/// List of model mapping to board identifiers.
|
|
/// Alphabetically sorted (!), for release order refer to the documentation.
|
|
///
|
|
STATIC OC_SB_MODEL_DESC mModelInformation[] = {
|
|
{ "j132", 0x0C }, ///< MacBookPro15,2
|
|
{ "j137", 0x0A }, ///< iMacPro1,1
|
|
{ "j140a", 0x37 }, ///< MacBookAir8,2
|
|
{ "j140k", 0x17 }, ///< MacBookAir8,1
|
|
{ "j152f", 0x3A }, ///< MacBookPro16,1
|
|
{ "j160", 0x0F }, ///< MacPro7,1
|
|
{ "j174", 0x0E }, ///< Macmini8,1
|
|
{ "j185", 0x22 }, ///< iMac20,1
|
|
{ "j185f", 0x23 }, ///< iMac20,2
|
|
{ "j213", 0x18 }, ///< MacBookPro15,4
|
|
{ "j214k", 0x3E }, ///< MacBookPro16,2
|
|
{ "j215", 0x38 }, ///< MacBookPro16,4
|
|
{ "j223", 0x3B }, ///< MacBookPro16,3
|
|
{ "j230k", 0x3F }, ///< MacBookAir9,1
|
|
{ "j680", 0x0B }, ///< MacBookPro15,1
|
|
{ "j780", 0x07 }, ///< MacBookPro15,3
|
|
{ OC_SB_MODEL_LEGACY, 0xF0 }, ///< Generic x86 from Big Sur
|
|
};
|
|
|
|
STATIC BOOLEAN mHasDigestOverride;
|
|
STATIC UINT8 mOriginalDigest[SHA384_DIGEST_SIZE];
|
|
STATIC UINT8 mOverrideDigest[SHA384_DIGEST_SIZE];
|
|
|
|
STATIC
|
|
OC_SB_MODEL_DESC *
|
|
InternalGetModelInfo (
|
|
IN CONST CHAR8 *Model
|
|
)
|
|
{
|
|
UINTN Start;
|
|
UINTN End;
|
|
UINTN Curr;
|
|
INTN Cmp;
|
|
|
|
//
|
|
// Classic binary search in a sorted string list.
|
|
//
|
|
Start = 0;
|
|
End = ARRAY_SIZE (mModelInformation) - 1;
|
|
|
|
while (Start <= End) {
|
|
Curr = (Start + End) / 2;
|
|
Cmp = AsciiStrCmp (mModelInformation[Curr].HardwareModel, Model);
|
|
|
|
if (Cmp == 0) {
|
|
return &mModelInformation[Curr];
|
|
} else if (Cmp < 0) {
|
|
Start = Curr + 1;
|
|
} else if (Curr > 0) {
|
|
End = Curr - 1;
|
|
} else {
|
|
//
|
|
// Even the first element does not match, required due to unsigned End.
|
|
//
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
bool
|
|
DERImg4VerifySignature (
|
|
DERByte *Modulus,
|
|
DERSize ModulusSize,
|
|
uint32_t Exponent,
|
|
const uint8_t *Signature,
|
|
size_t SignatureSize,
|
|
uint8_t *Data,
|
|
size_t DataSize,
|
|
const DERItem *AlgoOid
|
|
)
|
|
{
|
|
OC_SIG_HASH_TYPE AlgoType;
|
|
|
|
ASSERT (Modulus != NULL);
|
|
ASSERT (ModulusSize > 0);
|
|
ASSERT (Signature != NULL);
|
|
ASSERT (SignatureSize > 0);
|
|
ASSERT (Data != NULL);
|
|
ASSERT (DataSize > 0);
|
|
ASSERT (AlgoOid != NULL);
|
|
|
|
if (DEROidCompare (AlgoOid, &oidSha512Rsa)) {
|
|
AlgoType = OcSigHashTypeSha512;
|
|
} else if (DEROidCompare (AlgoOid, &oidSha384Rsa)) {
|
|
AlgoType = OcSigHashTypeSha384;
|
|
} else if (DEROidCompare (AlgoOid, &oidSha256Rsa)) {
|
|
AlgoType = OcSigHashTypeSha256;
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
return RsaVerifySigDataFromData (
|
|
Modulus,
|
|
ModulusSize,
|
|
Exponent,
|
|
Signature,
|
|
SignatureSize,
|
|
Data,
|
|
DataSize,
|
|
AlgoType
|
|
);
|
|
}
|
|
|
|
CONST CHAR8 *
|
|
OcAppleImg4GetHardwareModel (
|
|
IN CONST CHAR8 *ModelRequest
|
|
)
|
|
{
|
|
OC_SB_MODEL_DESC *ModelInfo;
|
|
|
|
ModelInfo = InternalGetModelInfo (ModelRequest);
|
|
if (ModelInfo != NULL) {
|
|
return ModelInfo->HardwareModel;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
OcAppleImg4Verify (
|
|
IN APPLE_IMG4_VERIFICATION_PROTOCOL *This,
|
|
IN UINT32 ObjType,
|
|
IN CONST VOID *ImageBuffer,
|
|
IN UINTN ImageSize,
|
|
IN UINT8 SbMode,
|
|
IN CONST VOID *ManifestBuffer,
|
|
IN UINTN ManifestSize,
|
|
OUT UINT8 **HashDigest OPTIONAL,
|
|
OUT UINTN *DigestSize OPTIONAL
|
|
)
|
|
{
|
|
DERReturn DerResult;
|
|
INTN CmpResult;
|
|
UINT8 Digest[SHA384_DIGEST_SIZE];
|
|
|
|
DERImg4ManifestInfo ManInfo;
|
|
|
|
if ( ((ImageBuffer == NULL) || (ImageSize == 0))
|
|
|| ((ManifestBuffer == NULL) || (ManifestSize == 0))
|
|
|| ((HashDigest == NULL) && (DigestSize != NULL))
|
|
|| ((HashDigest != NULL) && (DigestSize == NULL))
|
|
|| ( (SbMode != AppleImg4SbModeMedium)
|
|
&& (SbMode != AppleImg4SbModeFull)))
|
|
{
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
DerResult = DERImg4ParseManifest (
|
|
&ManInfo,
|
|
ManifestBuffer,
|
|
ManifestSize,
|
|
ObjType
|
|
);
|
|
if (DerResult != DR_Success) {
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"OCI4: Manifest (%u) for %08X parse fail with code %d\n",
|
|
ManifestSize,
|
|
ObjType,
|
|
DerResult
|
|
));
|
|
return EFI_SECURITY_VIOLATION;
|
|
}
|
|
|
|
CmpResult = -1;
|
|
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"OCI4: Verifying digest %u (%02X%02X%02X%02X) override %d %u (%02X%02X%02X%02X)\n",
|
|
ManInfo.imageDigestSize,
|
|
ManInfo.imageDigest[0],
|
|
ManInfo.imageDigest[1],
|
|
ManInfo.imageDigest[2],
|
|
ManInfo.imageDigest[3],
|
|
mHasDigestOverride,
|
|
SHA384_DIGEST_SIZE,
|
|
mOriginalDigest[0],
|
|
mOriginalDigest[1],
|
|
mOriginalDigest[2],
|
|
mOriginalDigest[3]
|
|
));
|
|
|
|
//
|
|
// Provide a route to accept our modified kernel as long as we can trust it is really it.
|
|
//
|
|
if ( mHasDigestOverride
|
|
&& (ManInfo.imageDigestSize == SHA384_DIGEST_SIZE)
|
|
&& (CompareMem (mOriginalDigest, ManInfo.imageDigest, sizeof (mOriginalDigest)) == 0))
|
|
{
|
|
Sha384 (Digest, ImageBuffer, ImageSize);
|
|
CmpResult = CompareMem (Digest, mOverrideDigest, sizeof (mOverrideDigest));
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"OCI4: Matching override %02X%02X%02X%02X with %02X%02X%02X%02X - %a\n",
|
|
mOverrideDigest[0],
|
|
mOverrideDigest[1],
|
|
mOverrideDigest[2],
|
|
mOverrideDigest[3],
|
|
Digest[0],
|
|
Digest[1],
|
|
Digest[2],
|
|
Digest[3],
|
|
CmpResult == 0 ? "success" : "failure"
|
|
));
|
|
if (CmpResult == 0) {
|
|
mHasDigestOverride = FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// As ManInfo.imageDigest is a buffer of static size, the bounds check to
|
|
// retrieve it acts as implicit sanitizing of ManInfo.imageDigestSize which
|
|
// can be considered trusted at this point.
|
|
//
|
|
if (CmpResult != 0) {
|
|
CmpResult = SigVerifyShaHashBySize (
|
|
ImageBuffer,
|
|
ImageSize,
|
|
ManInfo.imageDigest,
|
|
ManInfo.imageDigestSize
|
|
);
|
|
}
|
|
|
|
if (CmpResult != 0) {
|
|
return EFI_SECURITY_VIOLATION;
|
|
}
|
|
|
|
if (SbMode == AppleImg4SbModeMedium) {
|
|
if ( ManInfo.hasEcid
|
|
|| !ManInfo.hasXugs || (ManInfo.environment.xugs != mEnvInfo.xugs)
|
|
|| ( ManInfo.environment.internalUseOnlyUnit
|
|
&& (ManInfo.environment.internalUseOnlyUnit != mEnvInfo.internalUseOnlyUnit)))
|
|
{
|
|
return EFI_SECURITY_VIOLATION;
|
|
}
|
|
} else if (SbMode == AppleImg4SbModeFull) {
|
|
if ( !ManInfo.hasEcid || (ManInfo.environment.ecid != mEnvInfo.ecid)
|
|
|| ManInfo.hasXugs
|
|
|| ManInfo.environment.internalUseOnlyUnit)
|
|
{
|
|
return EFI_SECURITY_VIOLATION;
|
|
}
|
|
}
|
|
|
|
if ( (ManInfo.environment.boardId != mEnvInfo.boardId)
|
|
|| (ManInfo.environment.chipId != mEnvInfo.chipId)
|
|
|| (ManInfo.environment.certificateEpoch < mEnvInfo.certificateEpoch)
|
|
|| ((ManInfo.environment.productionStatus != mEnvInfo.productionStatus) && !ManInfo.environment.productionStatus)
|
|
|| ((ManInfo.environment.securityMode != mEnvInfo.securityMode) && !ManInfo.environment.securityMode)
|
|
|| (ManInfo.environment.securityDomain != mEnvInfo.securityDomain)
|
|
|| ( ManInfo.hasEffectiveProductionStatus
|
|
&& ((ManInfo.environment.effectiveProductionStatus != mEnvInfo.effectiveProductionStatus) && !ManInfo.environment.effectiveProductionStatus))
|
|
|| ( ManInfo.hasEffectiveSecurityMode
|
|
&& ((ManInfo.environment.effectiveSecurityMode != mEnvInfo.effectiveSecurityMode) && !ManInfo.environment.effectiveSecurityMode))
|
|
)
|
|
{
|
|
return EFI_SECURITY_VIOLATION;
|
|
}
|
|
|
|
if (HashDigest != NULL) {
|
|
*HashDigest = AllocateCopyPool (ManInfo.imageDigestSize, ManInfo.imageDigest);
|
|
if (*HashDigest == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
*DigestSize = ManInfo.imageDigestSize;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
OcAppleImg4RegisterOverride (
|
|
IN CONST UINT8 *OriginalDigest,
|
|
IN CONST UINT8 *Image,
|
|
IN UINT32 ImageSize
|
|
)
|
|
{
|
|
ASSERT (OriginalDigest != NULL);
|
|
ASSERT (Image != NULL);
|
|
ASSERT (ImageSize > 0);
|
|
|
|
mHasDigestOverride = TRUE;
|
|
CopyMem (mOriginalDigest, OriginalDigest, sizeof (mOriginalDigest));
|
|
Sha384 (mOverrideDigest, Image, ImageSize);
|
|
}
|
|
|
|
EFI_STATUS
|
|
OcAppleImg4BootstrapValues (
|
|
IN CONST CHAR8 *Model,
|
|
IN UINT64 Ecid OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
OC_SB_MODEL_DESC *SbInfo;
|
|
UINT8 Tmp;
|
|
|
|
ASSERT (Model != NULL);
|
|
SbInfo = InternalGetModelInfo (Model);
|
|
ASSERT (SbInfo != NULL); ///< Checked by calling OcAppleImg4GetHardwareModel.
|
|
|
|
//
|
|
// Predefine most of the values as they are common for all the models.
|
|
//
|
|
mEnvInfo.ecid = Ecid;
|
|
mEnvInfo.boardId = SbInfo->BoardId;
|
|
mEnvInfo.chipId = 0x8012;
|
|
mEnvInfo.certificateEpoch = 2;
|
|
mEnvInfo.securityDomain = 1;
|
|
mEnvInfo.productionStatus = TRUE;
|
|
mEnvInfo.securityMode = 1;
|
|
mEnvInfo.effectiveProductionStatus = TRUE;
|
|
mEnvInfo.effectiveSecurityMode = 1;
|
|
mEnvInfo.internalUseOnlyUnit = AsciiStrCmp (Model, OC_SB_MODEL_LEGACY) == 0;
|
|
mEnvInfo.xugs = 1;
|
|
mEnvInfo.allowMixNMatch = FALSE;
|
|
|
|
//
|
|
// Expose all the variables via NVRAM.
|
|
//
|
|
Status = gRT->SetVariable (
|
|
L"ApECID",
|
|
&gAppleSecureBootVariableGuid,
|
|
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
|
|
sizeof (mEnvInfo.ecid),
|
|
&mEnvInfo.ecid
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = gRT->SetVariable (
|
|
L"ApChipID",
|
|
&gAppleSecureBootVariableGuid,
|
|
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
|
|
sizeof (mEnvInfo.chipId),
|
|
&mEnvInfo.chipId
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Tmp = (UINT8)mEnvInfo.certificateEpoch;
|
|
Status = gRT->SetVariable (
|
|
L"CertificateEpoch",
|
|
&gAppleSecureBootVariableGuid,
|
|
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
|
|
sizeof (Tmp),
|
|
&Tmp
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = gRT->SetVariable (
|
|
L"ApBoardID",
|
|
&gAppleSecureBootVariableGuid,
|
|
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
|
|
sizeof (mEnvInfo.boardId),
|
|
&mEnvInfo.boardId
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = gRT->SetVariable (
|
|
L"ApSecurityDomain",
|
|
&gAppleSecureBootVariableGuid,
|
|
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
|
|
sizeof (mEnvInfo.securityDomain),
|
|
&mEnvInfo.securityDomain
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = gRT->SetVariable (
|
|
L"ApProductionStatus",
|
|
&gAppleSecureBootVariableGuid,
|
|
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
|
|
sizeof (mEnvInfo.productionStatus),
|
|
&mEnvInfo.productionStatus
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = gRT->SetVariable (
|
|
L"ApSecurityMode",
|
|
&gAppleSecureBootVariableGuid,
|
|
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
|
|
sizeof (mEnvInfo.securityMode),
|
|
&mEnvInfo.securityMode
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = gRT->SetVariable (
|
|
L"EffectiveProductionStatus",
|
|
&gAppleSecureBootVariableGuid,
|
|
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
|
|
sizeof (mEnvInfo.effectiveProductionStatus),
|
|
&mEnvInfo.effectiveProductionStatus
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = gRT->SetVariable (
|
|
L"EffectiveSecurityMode",
|
|
&gAppleSecureBootVariableGuid,
|
|
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
|
|
sizeof (mEnvInfo.effectiveSecurityMode),
|
|
&mEnvInfo.effectiveSecurityMode
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = gRT->SetVariable (
|
|
L"InternalUseOnlyUnit",
|
|
&gAppleSecureBootVariableGuid,
|
|
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
|
|
sizeof (mEnvInfo.internalUseOnlyUnit),
|
|
&mEnvInfo.internalUseOnlyUnit
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Tmp = (UINT8)mEnvInfo.allowMixNMatch;
|
|
Status = gRT->SetVariable (
|
|
L"MixNMatchPreventionStatus",
|
|
&gAppleSecureBootVariableGuid,
|
|
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
|
|
sizeof (Tmp),
|
|
&Tmp
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = gRT->SetVariable (
|
|
L"CryptoDigestMethod",
|
|
&gAppleSecureBootVariableGuid,
|
|
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
|
|
sizeof (mCryptoDigestMethod),
|
|
&mCryptoDigestMethod
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
APPLE_IMG4_VERIFICATION_PROTOCOL *
|
|
OcAppleImg4VerificationInstallProtocol (
|
|
IN BOOLEAN Reinstall
|
|
)
|
|
{
|
|
STATIC APPLE_IMG4_VERIFICATION_PROTOCOL Img4Verification = {
|
|
APPLE_IMG4_VERIFICATION_PROTOCOL_REVISION,
|
|
OcAppleImg4Verify
|
|
};
|
|
|
|
EFI_STATUS Status;
|
|
APPLE_IMG4_VERIFICATION_PROTOCOL *Protocol;
|
|
EFI_HANDLE Handle;
|
|
|
|
if (Reinstall) {
|
|
Status = OcUninstallAllProtocolInstances (&gAppleImg4VerificationProtocolGuid);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "OCI4: Uninstall failed: %r\n", Status));
|
|
return NULL;
|
|
}
|
|
} else {
|
|
Status = gBS->LocateProtocol (
|
|
&gAppleImg4VerificationProtocolGuid,
|
|
NULL,
|
|
(VOID **)&Protocol
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
return Protocol;
|
|
}
|
|
}
|
|
|
|
Handle = NULL;
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&Handle,
|
|
&gAppleImg4VerificationProtocolGuid,
|
|
(VOID **)&Img4Verification,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return NULL;
|
|
}
|
|
|
|
return &Img4Verification;
|
|
}
|