| /** @file | |
| TPM Platform Hierarchy configuration library. | |
| This library provides functions for customizing the TPM's Platform Hierarchy | |
| Authorization Value (platformAuth) and Platform Hierarchy Authorization | |
| Policy (platformPolicy) can be defined through this function. | |
| Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> | |
| Copyright (c) Microsoft Corporation.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| @par Specification Reference: | |
| https://trustedcomputinggroup.org/resource/tcg-tpm-v2-0-provisioning-guidance/ | |
| **/ | |
| #include <Uefi.h> | |
| #include <Library/BaseMemoryLib.h> | |
| #include <Library/DebugLib.h> | |
| #include <Library/MemoryAllocationLib.h> | |
| #include <Library/RngLib.h> | |
| #include <Library/Tpm2CommandLib.h> | |
| #include <Library/Tpm2DeviceLib.h> | |
| // | |
| // The authorization value may be no larger than the digest produced by the hash | |
| // algorithm used for context integrity. | |
| // | |
| UINT16 mAuthSize; | |
| /** | |
| Generate high-quality entropy source through RDRAND. | |
| @param[in] Length Size of the buffer, in bytes, to fill with. | |
| @param[out] Entropy Pointer to the buffer to store the entropy data. | |
| @retval EFI_SUCCESS Entropy generation succeeded. | |
| @retval EFI_NOT_READY Failed to request random data. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| RdRandGenerateEntropy ( | |
| IN UINTN Length, | |
| OUT UINT8 *Entropy | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN BlockCount; | |
| UINT64 Seed[2]; | |
| UINT8 *Ptr; | |
| Status = EFI_NOT_READY; | |
| BlockCount = Length / sizeof (Seed); | |
| Ptr = (UINT8 *)Entropy; | |
| // | |
| // Generate high-quality seed for DRBG Entropy | |
| // | |
| while (BlockCount > 0) { | |
| Status = GetRandomNumber128 (Seed); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| CopyMem (Ptr, Seed, sizeof (Seed)); | |
| BlockCount--; | |
| Ptr = Ptr + sizeof (Seed); | |
| } | |
| // | |
| // Populate the remained data as request. | |
| // | |
| Status = GetRandomNumber128 (Seed); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| CopyMem (Ptr, Seed, (Length % sizeof (Seed))); | |
| return Status; | |
| } | |
| /** | |
| This function returns the maximum size of TPM2B_AUTH; this structure is used for an authorization value | |
| and limits an authValue to being no larger than the largest digest produced by a TPM. | |
| @param[out] AuthSize Tpm2 Auth size | |
| @retval EFI_SUCCESS Auth size returned. | |
| @retval EFI_DEVICE_ERROR Can not return platform auth due to device error. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| GetAuthSize ( | |
| OUT UINT16 *AuthSize | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| TPML_PCR_SELECTION Pcrs; | |
| UINTN Index; | |
| UINT16 DigestSize; | |
| Status = EFI_SUCCESS; | |
| while (mAuthSize == 0) { | |
| mAuthSize = SHA1_DIGEST_SIZE; | |
| ZeroMem (&Pcrs, sizeof (TPML_PCR_SELECTION)); | |
| Status = Tpm2GetCapabilityPcrs (&Pcrs); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "Tpm2GetCapabilityPcrs fail!\n")); | |
| break; | |
| } | |
| DEBUG ((DEBUG_ERROR, "Tpm2GetCapabilityPcrs - %08x\n", Pcrs.count)); | |
| for (Index = 0; Index < Pcrs.count; Index++) { | |
| DEBUG ((DEBUG_ERROR, "alg - %x\n", Pcrs.pcrSelections[Index].hash)); | |
| switch (Pcrs.pcrSelections[Index].hash) { | |
| case TPM_ALG_SHA1: | |
| DigestSize = SHA1_DIGEST_SIZE; | |
| break; | |
| case TPM_ALG_SHA256: | |
| DigestSize = SHA256_DIGEST_SIZE; | |
| break; | |
| case TPM_ALG_SHA384: | |
| DigestSize = SHA384_DIGEST_SIZE; | |
| break; | |
| case TPM_ALG_SHA512: | |
| DigestSize = SHA512_DIGEST_SIZE; | |
| break; | |
| case TPM_ALG_SM3_256: | |
| DigestSize = SM3_256_DIGEST_SIZE; | |
| break; | |
| default: | |
| DigestSize = SHA1_DIGEST_SIZE; | |
| break; | |
| } | |
| if (DigestSize > mAuthSize) { | |
| mAuthSize = DigestSize; | |
| } | |
| } | |
| break; | |
| } | |
| *AuthSize = mAuthSize; | |
| return Status; | |
| } | |
| /** | |
| Set PlatformAuth to random value. | |
| **/ | |
| VOID | |
| RandomizePlatformAuth ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINT16 AuthSize; | |
| TPM2B_AUTH NewPlatformAuth; | |
| // | |
| // Send Tpm2HierarchyChange Auth with random value to avoid PlatformAuth being null | |
| // | |
| GetAuthSize (&AuthSize); | |
| NewPlatformAuth.size = AuthSize; | |
| // | |
| // Create the random bytes in the destination buffer | |
| // | |
| RdRandGenerateEntropy (NewPlatformAuth.size, NewPlatformAuth.buffer); | |
| // | |
| // Send Tpm2HierarchyChangeAuth command with the new Auth value | |
| // | |
| Status = Tpm2HierarchyChangeAuth (TPM_RH_PLATFORM, NULL, &NewPlatformAuth); | |
| DEBUG ((DEBUG_INFO, "Tpm2HierarchyChangeAuth Result: - %r\n", Status)); | |
| ZeroMem (NewPlatformAuth.buffer, AuthSize); | |
| } | |
| /** | |
| Disable the TPM platform hierarchy. | |
| @retval EFI_SUCCESS The TPM was disabled successfully. | |
| @retval Others An error occurred attempting to disable the TPM platform hierarchy. | |
| **/ | |
| EFI_STATUS | |
| DisableTpmPlatformHierarchy ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| // Make sure that we have use of the TPM. | |
| Status = Tpm2RequestUseTpm (); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "%a:%a() - Tpm2RequestUseTpm Failed! %r\n", gEfiCallerBaseName, __func__, Status)); | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } | |
| // Let's do what we can to shut down the hierarchies. | |
| // Disable the PH NV. | |
| // IMPORTANT NOTE: We *should* be able to disable the PH NV here, but TPM parts have | |
| // been known to store the EK cert in the PH NV. If we disable it, the | |
| // EK cert will be unreadable. | |
| // Disable the PH. | |
| Status = Tpm2HierarchyControl ( | |
| TPM_RH_PLATFORM, // AuthHandle | |
| NULL, // AuthSession | |
| TPM_RH_PLATFORM, // Hierarchy | |
| NO // State | |
| ); | |
| DEBUG ((DEBUG_VERBOSE, "%a:%a() - Disable PH = %r\n", gEfiCallerBaseName, __func__, Status)); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "%a:%a() - Disable PH Failed! %r\n", gEfiCallerBaseName, __func__, Status)); | |
| ASSERT_EFI_ERROR (Status); | |
| } | |
| return Status; | |
| } | |
| /** | |
| This service defines the configuration of the Platform Hierarchy Authorization Value (platformAuth) | |
| and Platform Hierarchy Authorization Policy (platformPolicy). | |
| **/ | |
| VOID | |
| EFIAPI | |
| ConfigureTpmPlatformHierarchy ( | |
| ) | |
| { | |
| if (PcdGetBool (PcdRandomizePlatformHierarchy)) { | |
| // | |
| // Send Tpm2HierarchyChange Auth with random value to avoid PlatformAuth being null | |
| // | |
| RandomizePlatformAuth (); | |
| } else { | |
| // | |
| // Disable the hierarchy entirely (do not randomize it) | |
| // | |
| DisableTpmPlatformHierarchy (); | |
| } | |
| } |