2 This driver verifies and reports OBB FVs.
4 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "FvReportPei.h"
11 STATIC CONST HASH_ALG_INFO mHashAlgInfo
[] = {
12 { TPM_ALG_SHA256
, SHA256_DIGEST_SIZE
, Sha256Init
, Sha256Update
, Sha256Final
, Sha256HashAll
}, // 000B
13 { TPM_ALG_SHA384
, SHA384_DIGEST_SIZE
, Sha384Init
, Sha384Update
, Sha384Final
, Sha384HashAll
}, // 000C
14 { TPM_ALG_SHA512
, SHA512_DIGEST_SIZE
, Sha512Init
, Sha512Update
, Sha512Final
, Sha512HashAll
}, // 000D
18 Find hash algorithm information from mHashAlgInfo according to given ID.
20 @param[in] HashAlgId Hash algorithm type id.
22 @retval Pointer to HASH_ALG_INFO if given hash algorithm is supported.
23 @retval NULL if given algorithm is not supported.
34 for (Index
= 0; Index
< ARRAY_SIZE (mHashAlgInfo
); ++Index
) {
35 if (mHashAlgInfo
[Index
].HashAlgId
== HashAlgId
) {
36 return &mHashAlgInfo
[Index
];
44 Install a EDKII_PEI_FIRMWARE_VOLUME_INFO_PREHASHED_FV_PPI instance so that
45 TCG driver may use to extend PCRs.
47 @param[in] FvBuffer Buffer containing the whole FV.
48 @param[in] FvLength Length of the FV.
49 @param[in] HashAlgoId Hash algorithm type id.
50 @param[in] HashSize Hash size.
51 @param[in] HashValue Hash value buffer.
64 EFI_PEI_PPI_DESCRIPTOR
*FvInfoPpiDescriptor
;
65 EDKII_PEI_FIRMWARE_VOLUME_INFO_PREHASHED_FV_PPI
*PreHashedFvPpi
;
69 PpiSize
= sizeof (EDKII_PEI_FIRMWARE_VOLUME_INFO_PREHASHED_FV_PPI
)
73 PreHashedFvPpi
= AllocatePool (PpiSize
);
74 ASSERT (PreHashedFvPpi
!= NULL
);
76 PreHashedFvPpi
->FvBase
= (UINT32
)(UINTN
)FvBuffer
;
77 PreHashedFvPpi
->FvLength
= (UINT32
)FvLength
;
78 PreHashedFvPpi
->Count
= 1;
80 HashInfo
= HASH_INFO_PTR (PreHashedFvPpi
);
81 HashInfo
->HashAlgoId
= HashAlgoId
;
82 HashInfo
->HashSize
= HashSize
;
83 CopyMem (HASH_VALUE_PTR (HashInfo
), HashValue
, HashSize
);
85 FvInfoPpiDescriptor
= AllocatePool (sizeof (EFI_PEI_PPI_DESCRIPTOR
));
86 ASSERT (FvInfoPpiDescriptor
!= NULL
);
88 FvInfoPpiDescriptor
->Guid
= &gEdkiiPeiFirmwareVolumeInfoPrehashedFvPpiGuid
;
89 FvInfoPpiDescriptor
->Flags
= EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
;
90 FvInfoPpiDescriptor
->Ppi
= (VOID
*)PreHashedFvPpi
;
92 Status
= PeiServicesInstallPpi (FvInfoPpiDescriptor
);
93 ASSERT_EFI_ERROR (Status
);
97 Calculate and verify hash value for given FV.
99 @param[in] HashInfo Hash information of the FV.
100 @param[in] FvInfo Information of FV used for verification.
101 @param[in] FvNumber Length of the FV.
102 @param[in] BootMode Length of the FV.
104 @retval EFI_SUCCESS The given FV is integrate.
105 @retval EFI_VOLUME_CORRUPTED The given FV is corrupted (hash mismatch).
106 @retval EFI_UNSUPPORTED The hash algorithm is not supported.
111 IN FV_HASH_INFO
*HashInfo
,
112 IN HASHED_FV_INFO
*FvInfo
,
114 IN EFI_BOOT_MODE BootMode
118 CONST HASH_ALG_INFO
*AlgInfo
;
124 if ((HashInfo
== NULL
) ||
125 (HashInfo
->HashSize
== 0) ||
126 (HashInfo
->HashAlgoId
== TPM_ALG_NULL
))
128 DEBUG ((DEBUG_INFO
, "Bypass FV hash verification\r\n"));
132 AlgInfo
= FindHashAlgInfo (HashInfo
->HashAlgoId
);
133 if ((AlgInfo
== NULL
) || (AlgInfo
->HashSize
!= HashInfo
->HashSize
)) {
136 "Unsupported or wrong hash algorithm: %04X (size=%d)\r\n",
137 HashInfo
->HashAlgoId
,
140 return EFI_UNSUPPORTED
;
143 ASSERT (FvInfo
!= NULL
);
144 ASSERT (FvNumber
> 0);
147 // We need a hash value for each FV as well as one for all FVs.
149 HashValue
= AllocateZeroPool (AlgInfo
->HashSize
* (FvNumber
+ 1));
150 ASSERT (HashValue
!= NULL
);
153 // Calculate hash value for each FV first.
155 FvHashValue
= HashValue
;
156 for (FvIndex
= 0; FvIndex
< FvNumber
; ++FvIndex
) {
158 // Not meant for verified boot and/or measured boot?
160 if (((FvInfo
[FvIndex
].Flag
& HASHED_FV_FLAG_VERIFIED_BOOT
) == 0) &&
161 ((FvInfo
[FvIndex
].Flag
& HASHED_FV_FLAG_MEASURED_BOOT
) == 0))
167 // Skip any FV not meant for current boot mode.
169 if ((FvInfo
[FvIndex
].Flag
& HASHED_FV_FLAG_SKIP_BOOT_MODE (BootMode
)) != 0) {
172 "Skip FV[%016lX] for boot mode[%d]\r\n",
173 FvInfo
[FvIndex
].Base
,
181 "Pre-hashed[alg=%04X,size=%d,flag=%016lX] FV: 0x%016lX (%08lX) (Flag=%016lX)\r\n",
182 HashInfo
->HashAlgoId
,
185 FvInfo
[FvIndex
].Base
,
186 FvInfo
[FvIndex
].Length
,
191 // Copy FV to permanent memory to avoid potential TOC/TOU.
193 FvBuffer
= AllocatePages (EFI_SIZE_TO_PAGES ((UINTN
)FvInfo
[FvIndex
].Length
));
194 ASSERT (FvBuffer
!= NULL
);
195 CopyMem (FvBuffer
, (CONST VOID
*)(UINTN
)FvInfo
[FvIndex
].Base
, (UINTN
)FvInfo
[FvIndex
].Length
);
197 if (!AlgInfo
->HashAll (FvBuffer
, (UINTN
)FvInfo
[FvIndex
].Length
, FvHashValue
)) {
198 Status
= EFI_ABORTED
;
203 // Report the FV measurement.
205 if ((FvInfo
[FvIndex
].Flag
& HASHED_FV_FLAG_MEASURED_BOOT
) != 0) {
206 InstallPreHashFvPpi (
208 (UINTN
)FvInfo
[FvIndex
].Length
,
209 HashInfo
->HashAlgoId
,
216 // Don't keep the hash value of current FV if we don't need to verify it.
218 if ((FvInfo
[FvIndex
].Flag
& HASHED_FV_FLAG_VERIFIED_BOOT
) != 0) {
219 FvHashValue
+= AlgInfo
->HashSize
;
223 // Use memory copy of the FV from now on.
225 FvInfo
[FvIndex
].Base
= (UINT64
)(UINTN
)FvBuffer
;
229 // Check final hash for all FVs.
231 if ((FvHashValue
== HashValue
) ||
232 (AlgInfo
->HashAll (HashValue
, FvHashValue
- HashValue
, FvHashValue
) &&
233 (CompareMem (HashInfo
->Hash
, FvHashValue
, AlgInfo
->HashSize
) == 0)))
235 Status
= EFI_SUCCESS
;
237 Status
= EFI_VOLUME_CORRUPTED
;
241 FreePool (HashValue
);
246 Report FV to PEI and/or DXE core for dispatch.
248 @param[in] FvInfo Information of a FV.
254 IN HASHED_FV_INFO
*FvInfo
257 CONST EFI_GUID
*FvFormat
;
259 if ((FvInfo
->Flag
& HASHED_FV_FLAG_REPORT_FV_HOB
) != 0) {
261 // Require DXE core to process this FV.
264 (EFI_PHYSICAL_ADDRESS
)FvInfo
->Base
,
267 DEBUG ((DEBUG_INFO
, "Reported FV HOB: %016lX (%08lX)\r\n", FvInfo
->Base
, FvInfo
->Length
));
270 if ((FvInfo
->Flag
& HASHED_FV_FLAG_REPORT_FV_INFO_PPI
) != 0) {
272 // Require PEI core to process this FV.
274 FvFormat
= &((EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)FvInfo
->Base
)->FileSystemGuid
;
275 PeiServicesInstallFvInfoPpi (
277 (VOID
*)(UINTN
)FvInfo
->Base
,
278 (UINT32
)FvInfo
->Length
,
282 DEBUG ((DEBUG_INFO
, "Reported FV PPI: %016lX (%08lX)\r\n", FvInfo
->Base
, FvInfo
->Length
));
287 Verify and report pre-hashed FVs.
289 Doing this must be at post-memory to make sure there's enough memory to hold
290 all FVs to be verified. This is necessary for mitigating TOCTOU issue.
292 This function will never return if the verification is failed.
294 @param[in] StoredHashFvPpi Pointer to PPI containing hash information.
295 @param[in] BootMode Current boot mode.
297 @retval Pointer to structure containing valid hash information for current boot mode.
298 @retval NULL if there's no hash associated with current boot mode.
303 IN EDKII_PEI_FIRMWARE_VOLUME_INFO_STORED_HASH_FV_PPI
*StoredHashFvPpi
,
304 IN EFI_BOOT_MODE BootMode
307 FV_HASH_INFO
*HashInfo
;
309 if ((StoredHashFvPpi
->HashInfo
.HashFlag
& FV_HASH_FLAG_BOOT_MODE (BootMode
)) != 0) {
310 HashInfo
= &StoredHashFvPpi
->HashInfo
;
319 Verify and report pre-hashed FVs.
321 Doing this must be at post-memory to make sure there's enough memory to hold
322 all FVs to be verified. This is necessary for mitigating TOCTOU issue.
324 This function will never return if the verification is failed.
326 @param[in] PeiServices General purpose services available to every PEIM.
327 @param[in] BootMode Current boot mode.
329 @retval EFI_SUCCESS The function completed successfully.
334 IN CONST EFI_PEI_SERVICES
**PeiServices
,
335 IN EFI_BOOT_MODE BootMode
339 EDKII_PEI_FIRMWARE_VOLUME_INFO_STORED_HASH_FV_PPI
*StoredHashFvPpi
;
340 FV_HASH_INFO
*HashInfo
;
344 // Check pre-hashed FV list
346 StoredHashFvPpi
= NULL
;
347 Status
= PeiServicesLocatePpi (
348 &gEdkiiPeiFirmwareVolumeInfoStoredHashFvPpiGuid
,
351 (VOID
**)&StoredHashFvPpi
353 if (!EFI_ERROR (Status
) && (StoredHashFvPpi
!= NULL
) && (StoredHashFvPpi
->FvNumber
> 0)) {
354 HashInfo
= GetHashInfo (StoredHashFvPpi
, BootMode
);
355 Status
= VerifyHashedFv (
357 StoredHashFvPpi
->FvInfo
,
358 StoredHashFvPpi
->FvNumber
,
361 if (!EFI_ERROR (Status
)) {
362 DEBUG ((DEBUG_INFO
, "OBB verification passed (%r)\r\n", Status
));
365 // Report the FVs to PEI core and/or DXE core.
367 for (FvIndex
= 0; FvIndex
< StoredHashFvPpi
->FvNumber
; ++FvIndex
) {
368 if ((StoredHashFvPpi
->FvInfo
[FvIndex
].Flag
369 & HASHED_FV_FLAG_SKIP_BOOT_MODE (BootMode
)) == 0)
371 ReportHashedFv (&StoredHashFvPpi
->FvInfo
[FvIndex
]);
377 PcdGet32 (PcdStatusCodeFvVerificationPass
)
380 DEBUG ((DEBUG_ERROR
, "ERROR: Failed to verify OBB FVs (%r)\r\n", Status
));
382 REPORT_STATUS_CODE_EX (
384 PcdGet32 (PcdStatusCodeFvVerificationFail
),
387 &gEdkiiPeiFirmwareVolumeInfoStoredHashFvPpiGuid
,
389 sizeof (*StoredHashFvPpi
)
392 ASSERT_EFI_ERROR (Status
);
395 DEBUG ((DEBUG_ERROR
, "ERROR: No/invalid StoredHashFvPpi located\r\n"));
397 ASSERT_EFI_ERROR (Status
);
398 ASSERT (StoredHashFvPpi
!= NULL
&& StoredHashFvPpi
->FvNumber
> 0);
400 Status
= EFI_NOT_FOUND
;
407 Main entry for FvReport PEIM.
409 @param[in] FileHandle Handle of the file being invoked.
410 @param[in] PeiServices Pointer to PEI Services table.
412 @retval EFI_SUCCESS If all FVs reported by StoredHashFvPpi are verified.
418 IN EFI_PEI_FILE_HANDLE FileHandle
,
419 IN CONST EFI_PEI_SERVICES
**PeiServices
423 EFI_BOOT_MODE BootMode
;
425 Status
= PeiServicesGetBootMode (&BootMode
);
426 ASSERT_EFI_ERROR (Status
);
428 Status
= CheckStoredHashFv (PeiServices
, BootMode
);
429 if (EFI_ERROR (Status
)) {
431 // Never pass control to left part of BIOS if any error.