]> git.proxmox.com Git - mirror_edk2.git/blame - SignedCapsulePkg/Library/EdkiiSystemCapsuleLib/EdkiiSystemCapsuleLib.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / SignedCapsulePkg / Library / EdkiiSystemCapsuleLib / EdkiiSystemCapsuleLib.c
CommitLineData
e29caef2
JY
1/** @file\r
2 EDKII System Capsule library.\r
3\r
4 EDKII System Capsule library instance.\r
5\r
6 CapsuleAuthenticateSystemFirmware(), ExtractAuthenticatedImage() will receive\r
7 untrusted input and do basic validation.\r
8\r
36db7492 9 Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
fbf06957 10 SPDX-License-Identifier: BSD-2-Clause-Patent\r
e29caef2
JY
11\r
12**/\r
13\r
14#include <PiDxe.h>\r
15\r
16#include <Guid/SystemResourceTable.h>\r
17#include <Guid/FirmwareContentsSigned.h>\r
18#include <Guid/WinCertificate.h>\r
19#include <Guid/EdkiiSystemFmpCapsule.h>\r
20#include <Guid/WinCertificate.h>\r
21#include <Guid/ImageAuthentication.h>\r
22\r
23#include <Library/BaseLib.h>\r
24#include <Library/BaseMemoryLib.h>\r
25#include <Library/DebugLib.h>\r
01ee04c4 26#include <Library/PcdLib.h>\r
e29caef2
JY
27#include <Library/MemoryAllocationLib.h>\r
28#include <Library/EdkiiSystemCapsuleLib.h>\r
29#include <Library/FmpAuthenticationLib.h>\r
30\r
31#include <Protocol/FirmwareManagement.h>\r
32\r
b8786489
MK
33EDKII_SYSTEM_FIRMWARE_IMAGE_DESCRIPTOR *mImageFmpInfo;\r
34UINTN mImageFmpInfoSize;\r
35EFI_GUID mEdkiiSystemFirmwareFileGuid;\r
e29caef2
JY
36\r
37/**\r
38 Check if a block of buffer is erased.\r
39\r
40 @param[in] ErasePolarity Erase polarity attribute of the firmware volume\r
41 @param[in] InBuffer The buffer to be checked\r
42 @param[in] BufferSize Size of the buffer in bytes\r
43\r
44 @retval TRUE The block of buffer is erased\r
45 @retval FALSE The block of buffer is not erased\r
46**/\r
47BOOLEAN\r
48IsBufferErased (\r
b8786489
MK
49 IN UINT8 ErasePolarity,\r
50 IN VOID *InBuffer,\r
51 IN UINTN BufferSize\r
e29caef2
JY
52 )\r
53{\r
b8786489
MK
54 UINTN Count;\r
55 UINT8 EraseByte;\r
56 UINT8 *Buffer;\r
e29caef2 57\r
b8786489 58 if (ErasePolarity == 1) {\r
e29caef2
JY
59 EraseByte = 0xFF;\r
60 } else {\r
61 EraseByte = 0;\r
62 }\r
63\r
64 Buffer = InBuffer;\r
65 for (Count = 0; Count < BufferSize; Count++) {\r
66 if (Buffer[Count] != EraseByte) {\r
67 return FALSE;\r
68 }\r
69 }\r
70\r
71 return TRUE;\r
72}\r
73\r
74/**\r
75 Get Section buffer pointer by SectionType and SectionInstance.\r
76\r
77 @param[in] SectionBuffer The buffer of section\r
78 @param[in] SectionBufferSize The size of SectionBuffer in bytes\r
79 @param[in] SectionType The SectionType of Section to be found\r
80 @param[in] SectionInstance The Instance of Section to be found\r
81 @param[out] OutSectionBuffer The section found, including SECTION_HEADER\r
82 @param[out] OutSectionSize The size of section found, including SECTION_HEADER\r
83\r
84 @retval TRUE The FFS buffer is found.\r
85 @retval FALSE The FFS buffer is not found.\r
86**/\r
87BOOLEAN\r
88GetSectionByType (\r
b8786489
MK
89 IN VOID *SectionBuffer,\r
90 IN UINT32 SectionBufferSize,\r
91 IN EFI_SECTION_TYPE SectionType,\r
92 IN UINTN SectionInstance,\r
93 OUT VOID **OutSectionBuffer,\r
94 OUT UINTN *OutSectionSize\r
e29caef2
JY
95 )\r
96{\r
b8786489
MK
97 EFI_COMMON_SECTION_HEADER *SectionHeader;\r
98 UINTN SectionSize;\r
99 UINTN Instance;\r
e29caef2
JY
100\r
101 DEBUG ((DEBUG_INFO, "GetSectionByType - Buffer: 0x%08x - 0x%08x\n", SectionBuffer, SectionBufferSize));\r
102\r
103 //\r
104 // Find Section\r
105 //\r
106 SectionHeader = SectionBuffer;\r
107\r
108 Instance = 0;\r
109 while ((UINTN)SectionHeader < (UINTN)SectionBuffer + SectionBufferSize) {\r
110 DEBUG ((DEBUG_INFO, "GetSectionByType - Section: 0x%08x\n", SectionHeader));\r
b8786489
MK
111 if (IS_SECTION2 (SectionHeader)) {\r
112 SectionSize = SECTION2_SIZE (SectionHeader);\r
e29caef2 113 } else {\r
b8786489 114 SectionSize = SECTION_SIZE (SectionHeader);\r
e29caef2
JY
115 }\r
116\r
117 if (SectionHeader->Type == SectionType) {\r
118 if (Instance == SectionInstance) {\r
119 *OutSectionBuffer = (UINT8 *)SectionHeader;\r
b8786489
MK
120 *OutSectionSize = SectionSize;\r
121 DEBUG ((DEBUG_INFO, "GetSectionByType - 0x%x - 0x%x\n", *OutSectionBuffer, *OutSectionSize));\r
e29caef2
JY
122 return TRUE;\r
123 } else {\r
b8786489 124 DEBUG ((DEBUG_INFO, "GetSectionByType - find section instance %x\n", Instance));\r
e29caef2
JY
125 Instance++;\r
126 }\r
127 } else {\r
128 //\r
129 // Skip other section type\r
130 //\r
131 DEBUG ((DEBUG_INFO, "GetSectionByType - other section type 0x%x\n", SectionHeader->Type));\r
132 }\r
133\r
134 //\r
135 // Next Section\r
136 //\r
b8786489 137 SectionHeader = (EFI_COMMON_SECTION_HEADER *)((UINTN)SectionHeader + ALIGN_VALUE (SectionSize, 4));\r
e29caef2
JY
138 }\r
139\r
140 return FALSE;\r
141}\r
142\r
143/**\r
144 Get FFS buffer pointer by FileName GUID and FileType.\r
145\r
146 @param[in] FdStart The System Firmware FD image\r
147 @param[in] FdSize The size of System Firmware FD image\r
148 @param[in] FileName The FileName GUID of FFS to be found\r
149 @param[in] Type The FileType of FFS to be found\r
150 @param[out] OutFfsBuffer The FFS buffer found, including FFS_FILE_HEADER\r
151 @param[out] OutFfsBufferSize The size of FFS buffer found, including FFS_FILE_HEADER\r
152\r
153 @retval TRUE The FFS buffer is found.\r
154 @retval FALSE The FFS buffer is not found.\r
155**/\r
156BOOLEAN\r
157GetFfsByName (\r
b8786489
MK
158 IN VOID *FdStart,\r
159 IN UINTN FdSize,\r
160 IN EFI_GUID *FileName,\r
161 IN EFI_FV_FILETYPE Type,\r
162 OUT VOID **OutFfsBuffer,\r
163 OUT UINTN *OutFfsBufferSize\r
e29caef2
JY
164 )\r
165{\r
b8786489
MK
166 UINTN FvSize;\r
167 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r
168 EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader;\r
169 EFI_FFS_FILE_HEADER *FfsHeader;\r
170 UINT32 FfsSize;\r
171 UINTN TestLength;\r
172 BOOLEAN FvFound;\r
e29caef2
JY
173\r
174 DEBUG ((DEBUG_INFO, "GetFfsByName - FV: 0x%08x - 0x%08x\n", (UINTN)FdStart, (UINTN)FdSize));\r
175\r
b8786489 176 FvFound = FALSE;\r
e29caef2
JY
177 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FdStart;\r
178 while ((UINTN)FvHeader < (UINTN)FdStart + FdSize - 1) {\r
179 FvSize = (UINTN)FdStart + FdSize - (UINTN)FvHeader;\r
180\r
181 if (FvHeader->Signature != EFI_FVH_SIGNATURE) {\r
182 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)FvHeader + SIZE_4KB);\r
183 continue;\r
184 }\r
b8786489
MK
185\r
186 DEBUG ((DEBUG_INFO, "checking FV....0x%08x - 0x%x\n", FvHeader, FvHeader->FvLength));\r
e29caef2
JY
187 FvFound = TRUE;\r
188 if (FvHeader->FvLength > FvSize) {\r
b8786489 189 DEBUG ((DEBUG_ERROR, "GetFfsByName - FvSize: 0x%08x, MaxSize - 0x%08x\n", (UINTN)FvHeader->FvLength, (UINTN)FvSize));\r
e29caef2
JY
190 return FALSE;\r
191 }\r
b8786489 192\r
e29caef2
JY
193 FvSize = (UINTN)FvHeader->FvLength;\r
194\r
195 //\r
196 // Find FFS\r
197 //\r
198 if (FvHeader->ExtHeaderOffset != 0) {\r
199 FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)((UINT8 *)FvHeader + FvHeader->ExtHeaderOffset);\r
b8786489 200 FfsHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FvExtHeader + FvExtHeader->ExtHeaderSize);\r
e29caef2
JY
201 } else {\r
202 FfsHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FvHeader + FvHeader->HeaderLength);\r
203 }\r
b8786489
MK
204\r
205 FfsHeader = (EFI_FFS_FILE_HEADER *)((UINTN)FvHeader + ALIGN_VALUE ((UINTN)FfsHeader - (UINTN)FvHeader, 8));\r
e29caef2
JY
206\r
207 while ((UINTN)FfsHeader < (UINTN)FvHeader + FvSize - 1) {\r
b8786489 208 DEBUG ((DEBUG_INFO, "GetFfsByName - FFS: 0x%08x\n", FfsHeader));\r
e29caef2 209 TestLength = (UINTN)((UINTN)FvHeader + FvSize - (UINTN)FfsHeader);\r
b8786489
MK
210 if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {\r
211 TestLength = sizeof (EFI_FFS_FILE_HEADER);\r
e29caef2 212 }\r
b8786489
MK
213\r
214 if (IsBufferErased (1, FfsHeader, TestLength)) {\r
e29caef2
JY
215 break;\r
216 }\r
217\r
b8786489
MK
218 if (IS_FFS_FILE2 (FfsHeader)) {\r
219 FfsSize = FFS_FILE2_SIZE (FfsHeader);\r
e29caef2 220 } else {\r
b8786489 221 FfsSize = FFS_FILE_SIZE (FfsHeader);\r
e29caef2
JY
222 }\r
223\r
b8786489
MK
224 if (CompareGuid (FileName, &FfsHeader->Name) &&\r
225 ((Type == EFI_FV_FILETYPE_ALL) || (FfsHeader->Type == Type)))\r
226 {\r
227 *OutFfsBuffer = FfsHeader;\r
e29caef2
JY
228 *OutFfsBufferSize = FfsSize;\r
229 return TRUE;\r
230 } else {\r
231 //\r
232 // Any other type is not allowed\r
233 //\r
b8786489 234 DEBUG ((DEBUG_INFO, "GetFfsByName - other FFS type 0x%x, name %g\n", FfsHeader->Type, &FfsHeader->Name));\r
e29caef2
JY
235 }\r
236\r
237 //\r
238 // Next File\r
239 //\r
b8786489 240 FfsHeader = (EFI_FFS_FILE_HEADER *)((UINTN)FfsHeader + ALIGN_VALUE (FfsSize, 8));\r
e29caef2
JY
241 }\r
242\r
243 //\r
244 // Next FV\r
245 //\r
246 FvHeader = (VOID *)(UINTN)((UINTN)FvHeader + FvHeader->FvLength);\r
e29caef2
JY
247 }\r
248\r
249 if (!FvFound) {\r
b8786489 250 DEBUG ((DEBUG_ERROR, "GetFfsByName - NO FV Found\n"));\r
e29caef2 251 }\r
b8786489 252\r
e29caef2
JY
253 return FALSE;\r
254}\r
255\r
256/**\r
257 Extract the driver FV from an authenticated image.\r
258\r
259 @param[in] AuthenticatedImage The authenticated capsule image.\r
260 @param[in] AuthenticatedImageSize The size of the authenticated capsule image in bytes.\r
261 @param[out] DriverFvImage The driver FV image.\r
262 @param[out] DriverFvImageSize The size of the driver FV image in bytes.\r
263\r
264 @retval TRUE The driver Fv is extracted.\r
265 @retval FALSE The driver Fv is not extracted.\r
266**/\r
267BOOLEAN\r
268EFIAPI\r
269ExtractDriverFvImage (\r
b8786489
MK
270 IN VOID *AuthenticatedImage,\r
271 IN UINTN AuthenticatedImageSize,\r
272 OUT VOID **DriverFvImage,\r
273 OUT UINTN *DriverFvImageSize\r
e29caef2
JY
274 )\r
275{\r
b8786489
MK
276 BOOLEAN Result;\r
277 UINT32 FileHeaderSize;\r
e29caef2 278\r
b8786489 279 *DriverFvImage = NULL;\r
e29caef2
JY
280 *DriverFvImageSize = 0;\r
281\r
b8786489 282 Result = GetFfsByName (AuthenticatedImage, AuthenticatedImageSize, &gEdkiiSystemFmpCapsuleDriverFvFileGuid, EFI_FV_FILETYPE_RAW, DriverFvImage, DriverFvImageSize);\r
e29caef2
JY
283 if (!Result) {\r
284 return FALSE;\r
285 }\r
286\r
b8786489
MK
287 if (IS_FFS_FILE2 (*DriverFvImage)) {\r
288 FileHeaderSize = sizeof (EFI_FFS_FILE_HEADER2);\r
e29caef2 289 } else {\r
b8786489 290 FileHeaderSize = sizeof (EFI_FFS_FILE_HEADER);\r
e29caef2 291 }\r
b8786489
MK
292\r
293 *DriverFvImage = (UINT8 *)*DriverFvImage + FileHeaderSize;\r
e29caef2
JY
294 *DriverFvImageSize = *DriverFvImageSize - FileHeaderSize;\r
295\r
296 return Result;\r
297}\r
298\r
299/**\r
300 Extract the config image from an authenticated image.\r
301\r
302 @param[in] AuthenticatedImage The authenticated capsule image.\r
303 @param[in] AuthenticatedImageSize The size of the authenticated capsule image in bytes.\r
304 @param[out] ConfigImage The config image.\r
305 @param[out] ConfigImageSize The size of the config image in bytes.\r
306\r
307 @retval TRUE The config image is extracted.\r
308 @retval FALSE The config image is not extracted.\r
309**/\r
310BOOLEAN\r
311EFIAPI\r
312ExtractConfigImage (\r
b8786489
MK
313 IN VOID *AuthenticatedImage,\r
314 IN UINTN AuthenticatedImageSize,\r
315 OUT VOID **ConfigImage,\r
316 OUT UINTN *ConfigImageSize\r
e29caef2
JY
317 )\r
318{\r
b8786489
MK
319 BOOLEAN Result;\r
320 UINT32 FileHeaderSize;\r
e29caef2 321\r
b8786489 322 *ConfigImage = NULL;\r
e29caef2
JY
323 *ConfigImageSize = 0;\r
324\r
b8786489 325 Result = GetFfsByName (AuthenticatedImage, AuthenticatedImageSize, &gEdkiiSystemFmpCapsuleConfigFileGuid, EFI_FV_FILETYPE_RAW, ConfigImage, ConfigImageSize);\r
e29caef2
JY
326 if (!Result) {\r
327 return FALSE;\r
328 }\r
329\r
b8786489
MK
330 if (IS_FFS_FILE2 (*ConfigImage)) {\r
331 FileHeaderSize = sizeof (EFI_FFS_FILE_HEADER2);\r
e29caef2 332 } else {\r
b8786489 333 FileHeaderSize = sizeof (EFI_FFS_FILE_HEADER);\r
e29caef2 334 }\r
b8786489
MK
335\r
336 *ConfigImage = (UINT8 *)*ConfigImage + FileHeaderSize;\r
e29caef2
JY
337 *ConfigImageSize = *ConfigImageSize - FileHeaderSize;\r
338\r
339 return Result;\r
340}\r
341\r
342/**\r
343 Extract the authenticated image from an FMP capsule image.\r
344\r
345 Caution: This function may receive untrusted input.\r
346\r
347 @param[in] Image The FMP capsule image, including EFI_FIRMWARE_IMAGE_AUTHENTICATION.\r
348 @param[in] ImageSize The size of FMP capsule image in bytes.\r
349 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
350 @param[out] AuthenticatedImage The authenticated capsule image, excluding EFI_FIRMWARE_IMAGE_AUTHENTICATION.\r
351 @param[out] AuthenticatedImageSize The size of the authenticated capsule image in bytes.\r
352\r
353 @retval TRUE The authenticated image is extracted.\r
354 @retval FALSE The authenticated image is not extracted.\r
355**/\r
356BOOLEAN\r
357EFIAPI\r
358ExtractAuthenticatedImage (\r
b8786489
MK
359 IN VOID *Image,\r
360 IN UINTN ImageSize,\r
361 OUT UINT32 *LastAttemptStatus,\r
362 OUT VOID **AuthenticatedImage,\r
363 OUT UINTN *AuthenticatedImageSize\r
e29caef2
JY
364 )\r
365{\r
b8786489
MK
366 EFI_FIRMWARE_IMAGE_AUTHENTICATION *ImageAuth;\r
367 EFI_STATUS Status;\r
368 GUID *CertType;\r
369 VOID *PublicKeyData;\r
370 UINTN PublicKeyDataLength;\r
e29caef2 371\r
b8786489 372 DEBUG ((DEBUG_INFO, "ExtractAuthenticatedImage - Image: 0x%08x - 0x%08x\n", (UINTN)Image, (UINTN)ImageSize));\r
e29caef2
JY
373\r
374 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
375 if ((Image == NULL) || (ImageSize == 0)) {\r
376 return FALSE;\r
377 }\r
378\r
379 ImageAuth = (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image;\r
b8786489
MK
380 if (ImageSize < sizeof (EFI_FIRMWARE_IMAGE_AUTHENTICATION)) {\r
381 DEBUG ((DEBUG_ERROR, "ExtractAuthenticatedImage - ImageSize too small\n"));\r
e29caef2
JY
382 return FALSE;\r
383 }\r
b8786489
MK
384\r
385 if (ImageAuth->AuthInfo.Hdr.dwLength <= OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)) {\r
386 DEBUG ((DEBUG_ERROR, "ExtractAuthenticatedImage - dwLength too small\n"));\r
e29caef2
JY
387 return FALSE;\r
388 }\r
b8786489
MK
389\r
390 if ((UINTN)ImageAuth->AuthInfo.Hdr.dwLength > MAX_UINTN - sizeof (UINT64)) {\r
391 DEBUG ((DEBUG_ERROR, "ExtractAuthenticatedImage - dwLength too big\n"));\r
e29caef2
JY
392 return FALSE;\r
393 }\r
b8786489
MK
394\r
395 if (ImageSize <= sizeof (ImageAuth->MonotonicCount) + ImageAuth->AuthInfo.Hdr.dwLength) {\r
396 DEBUG ((DEBUG_ERROR, "ExtractAuthenticatedImage - ImageSize too small\n"));\r
e29caef2
JY
397 return FALSE;\r
398 }\r
b8786489 399\r
e29caef2 400 if (ImageAuth->AuthInfo.Hdr.wRevision != 0x0200) {\r
b8786489 401 DEBUG ((DEBUG_ERROR, "ExtractAuthenticatedImage - wRevision: 0x%02x, expect - 0x%02x\n", (UINTN)ImageAuth->AuthInfo.Hdr.wRevision, (UINTN)0x0200));\r
e29caef2
JY
402 return FALSE;\r
403 }\r
b8786489 404\r
e29caef2 405 if (ImageAuth->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) {\r
b8786489 406 DEBUG ((DEBUG_ERROR, "ExtractAuthenticatedImage - wCertificateType: 0x%02x, expect - 0x%02x\n", (UINTN)ImageAuth->AuthInfo.Hdr.wCertificateType, (UINTN)WIN_CERT_TYPE_EFI_GUID));\r
e29caef2
JY
407 return FALSE;\r
408 }\r
409\r
410 CertType = &ImageAuth->AuthInfo.CertType;\r
b8786489
MK
411 DEBUG ((DEBUG_INFO, "ExtractAuthenticatedImage - CertType: %g\n", CertType));\r
412\r
413 if (CompareGuid (&gEfiCertPkcs7Guid, CertType)) {\r
414 PublicKeyData = PcdGetPtr (PcdPkcs7CertBuffer);\r
415 PublicKeyDataLength = PcdGetSize (PcdPkcs7CertBuffer);\r
416 } else if (CompareGuid (&gEfiCertTypeRsa2048Sha256Guid, CertType)) {\r
417 PublicKeyData = PcdGetPtr (PcdRsa2048Sha256PublicKeyBuffer);\r
418 PublicKeyDataLength = PcdGetSize (PcdRsa2048Sha256PublicKeyBuffer);\r
e29caef2
JY
419 } else {\r
420 return FALSE;\r
421 }\r
b8786489 422\r
7e6e4f96
JY
423 ASSERT (PublicKeyData != NULL);\r
424 ASSERT (PublicKeyDataLength != 0);\r
e29caef2 425\r
b8786489 426 Status = AuthenticateFmpImage (\r
e29caef2
JY
427 ImageAuth,\r
428 ImageSize,\r
429 PublicKeyData,\r
430 PublicKeyDataLength\r
431 );\r
432 switch (Status) {\r
b8786489
MK
433 case RETURN_SUCCESS:\r
434 *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
435 break;\r
436 case RETURN_SECURITY_VIOLATION:\r
437 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR;\r
438 break;\r
439 case RETURN_INVALID_PARAMETER:\r
440 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
441 break;\r
442 case RETURN_UNSUPPORTED:\r
443 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
444 break;\r
445 case RETURN_OUT_OF_RESOURCES:\r
446 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
447 break;\r
448 default:\r
449 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
450 break;\r
451 }\r
452\r
453 if (EFI_ERROR (Status)) {\r
e29caef2
JY
454 return FALSE;\r
455 }\r
456\r
457 if (AuthenticatedImage != NULL) {\r
b8786489 458 *AuthenticatedImage = (UINT8 *)ImageAuth + ImageAuth->AuthInfo.Hdr.dwLength + sizeof (ImageAuth->MonotonicCount);\r
e29caef2 459 }\r
b8786489 460\r
e29caef2 461 if (AuthenticatedImageSize != NULL) {\r
b8786489 462 *AuthenticatedImageSize = ImageSize - ImageAuth->AuthInfo.Hdr.dwLength - sizeof (ImageAuth->MonotonicCount);\r
e29caef2 463 }\r
b8786489 464\r
e29caef2
JY
465 return TRUE;\r
466}\r
467\r
468/**\r
469 Extract ImageFmpInfo from system firmware.\r
470\r
471 @param[in] SystemFirmwareImage The System Firmware image.\r
472 @param[in] SystemFirmwareImageSize The size of the System Firmware image in bytes.\r
473 @param[out] ImageFmpInfo The ImageFmpInfo.\r
474 @param[out] ImageFmpInfoSize The size of the ImageFmpInfo in bytes.\r
475\r
476 @retval TRUE The ImageFmpInfo is extracted.\r
477 @retval FALSE The ImageFmpInfo is not extracted.\r
478**/\r
479BOOLEAN\r
480EFIAPI\r
481ExtractSystemFirmwareImageFmpInfo (\r
b8786489
MK
482 IN VOID *SystemFirmwareImage,\r
483 IN UINTN SystemFirmwareImageSize,\r
484 OUT EDKII_SYSTEM_FIRMWARE_IMAGE_DESCRIPTOR **ImageFmpInfo,\r
485 OUT UINTN *ImageFmpInfoSize\r
e29caef2
JY
486 )\r
487{\r
b8786489
MK
488 BOOLEAN Result;\r
489 UINT32 SectionHeaderSize;\r
490 UINT32 FileHeaderSize;\r
e29caef2 491\r
b8786489 492 *ImageFmpInfo = NULL;\r
e29caef2
JY
493 *ImageFmpInfoSize = 0;\r
494\r
b8786489 495 Result = GetFfsByName (SystemFirmwareImage, SystemFirmwareImageSize, &gEdkiiSystemFirmwareImageDescriptorFileGuid, EFI_FV_FILETYPE_ALL, (VOID **)ImageFmpInfo, ImageFmpInfoSize);\r
e29caef2
JY
496 if (!Result) {\r
497 return FALSE;\r
498 }\r
b8786489 499\r
e29caef2 500 if (IS_FFS_FILE2 (*ImageFmpInfo)) {\r
b8786489 501 FileHeaderSize = sizeof (EFI_FFS_FILE_HEADER2);\r
e29caef2 502 } else {\r
b8786489 503 FileHeaderSize = sizeof (EFI_FFS_FILE_HEADER);\r
e29caef2 504 }\r
b8786489
MK
505\r
506 *ImageFmpInfo = (VOID *)((UINT8 *)*ImageFmpInfo + FileHeaderSize);\r
e29caef2
JY
507 *ImageFmpInfoSize = *ImageFmpInfoSize - FileHeaderSize;\r
508\r
b8786489 509 Result = GetSectionByType (*ImageFmpInfo, (UINT32)*ImageFmpInfoSize, EFI_SECTION_RAW, 0, (VOID **)ImageFmpInfo, ImageFmpInfoSize);\r
e29caef2
JY
510 if (!Result) {\r
511 return FALSE;\r
512 }\r
b8786489
MK
513\r
514 if (IS_SECTION2 (*ImageFmpInfo)) {\r
515 SectionHeaderSize = sizeof (EFI_RAW_SECTION2);\r
e29caef2 516 } else {\r
b8786489 517 SectionHeaderSize = sizeof (EFI_RAW_SECTION);\r
e29caef2 518 }\r
b8786489
MK
519\r
520 *ImageFmpInfo = (VOID *)((UINT8 *)*ImageFmpInfo + SectionHeaderSize);\r
e29caef2
JY
521 *ImageFmpInfoSize = *ImageFmpInfoSize - SectionHeaderSize;\r
522\r
523 return TRUE;\r
524}\r
525\r
526/**\r
527 Extract the System Firmware image from an authenticated image.\r
528\r
529 @param[in] AuthenticatedImage The authenticated capsule image.\r
530 @param[in] AuthenticatedImageSize The size of the authenticated capsule image in bytes.\r
531 @param[out] SystemFirmwareImage The System Firmware image.\r
532 @param[out] SystemFirmwareImageSize The size of the System Firmware image in bytes.\r
533\r
534 @retval TRUE The System Firmware image is extracted.\r
535 @retval FALSE The System Firmware image is not extracted.\r
536**/\r
537BOOLEAN\r
538EFIAPI\r
539ExtractSystemFirmwareImage (\r
b8786489
MK
540 IN VOID *AuthenticatedImage,\r
541 IN UINTN AuthenticatedImageSize,\r
542 OUT VOID **SystemFirmwareImage,\r
543 OUT UINTN *SystemFirmwareImageSize\r
e29caef2
JY
544 )\r
545{\r
b8786489
MK
546 BOOLEAN Result;\r
547 UINT32 FileHeaderSize;\r
e29caef2 548\r
b8786489 549 *SystemFirmwareImage = NULL;\r
e29caef2
JY
550 *SystemFirmwareImageSize = 0;\r
551\r
b8786489 552 Result = GetFfsByName (AuthenticatedImage, AuthenticatedImageSize, &mEdkiiSystemFirmwareFileGuid, EFI_FV_FILETYPE_RAW, SystemFirmwareImage, SystemFirmwareImageSize);\r
e29caef2
JY
553 if (!Result) {\r
554 // no nested FV, just return all data.\r
b8786489 555 *SystemFirmwareImage = AuthenticatedImage;\r
e29caef2
JY
556 *SystemFirmwareImageSize = AuthenticatedImageSize;\r
557\r
558 return TRUE;\r
559 }\r
b8786489 560\r
e29caef2 561 if (IS_FFS_FILE2 (*SystemFirmwareImage)) {\r
b8786489 562 FileHeaderSize = sizeof (EFI_FFS_FILE_HEADER2);\r
e29caef2 563 } else {\r
b8786489 564 FileHeaderSize = sizeof (EFI_FFS_FILE_HEADER);\r
e29caef2 565 }\r
b8786489
MK
566\r
567 *SystemFirmwareImage = (UINT8 *)*SystemFirmwareImage + FileHeaderSize;\r
e29caef2
JY
568 *SystemFirmwareImageSize = *SystemFirmwareImageSize - FileHeaderSize;\r
569\r
570 return Result;\r
571}\r
572\r
573/**\r
574 Authenticated system firmware FMP capsule image.\r
575\r
576 Caution: This function may receive untrusted input.\r
577\r
578 @param[in] Image The FMP capsule image, including EFI_FIRMWARE_IMAGE_AUTHENTICATION.\r
579 @param[in] ImageSize The size of FMP capsule image in bytes.\r
580 @param[in] ForceVersionMatch TRUE: The version of capsule must be as same as the version of current image.\r
581 FALSE: The version of capsule must be as same as greater than the lowest\r
582 supported version of current image.\r
583 @param[out] LastAttemptVersion The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
584 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
585 @param[out] AuthenticatedImage The authenticated capsule image, excluding EFI_FIRMWARE_IMAGE_AUTHENTICATION.\r
586 @param[out] AuthenticatedImageSize The size of the authenticated capsule image in bytes.\r
587\r
588 @retval TRUE Authentication passes and the authenticated image is extracted.\r
589 @retval FALSE Authentication fails and the authenticated image is not extracted.\r
590**/\r
591EFI_STATUS\r
592EFIAPI\r
593CapsuleAuthenticateSystemFirmware (\r
b8786489
MK
594 IN VOID *Image,\r
595 IN UINTN ImageSize,\r
596 IN BOOLEAN ForceVersionMatch,\r
597 OUT UINT32 *LastAttemptVersion,\r
598 OUT UINT32 *LastAttemptStatus,\r
599 OUT VOID **AuthenticatedImage,\r
600 OUT UINTN *AuthenticatedImageSize\r
e29caef2
JY
601 )\r
602{\r
b8786489
MK
603 BOOLEAN Result;\r
604 EDKII_SYSTEM_FIRMWARE_IMAGE_DESCRIPTOR *ImageFmpInfo;\r
605 UINTN ImageFmpInfoSize;\r
606 EDKII_SYSTEM_FIRMWARE_IMAGE_DESCRIPTOR *CurrentImageFmpInfo;\r
607 UINTN CurrentImageFmpInfoSize;\r
608 VOID *SystemFirmwareImage;\r
609 UINTN SystemFirmwareImageSize;\r
e29caef2
JY
610\r
611 *LastAttemptVersion = 0;\r
612\r
613 //\r
614 // NOTE: This function need run in an isolated environment.\r
615 // Do not touch FMP protocol and its private structure.\r
616 //\r
01ee04c4 617 if (mImageFmpInfo == NULL) {\r
b8786489 618 DEBUG ((DEBUG_INFO, "ImageFmpInfo is not set\n"));\r
01ee04c4
LG
619 return EFI_SECURITY_VIOLATION;\r
620 }\r
e29caef2 621\r
b8786489 622 Result = ExtractAuthenticatedImage ((VOID *)Image, ImageSize, LastAttemptStatus, AuthenticatedImage, AuthenticatedImageSize);\r
e29caef2 623 if (!Result) {\r
b8786489 624 DEBUG ((DEBUG_INFO, "ExtractAuthenticatedImage - fail\n"));\r
e29caef2
JY
625 return EFI_SECURITY_VIOLATION;\r
626 }\r
627\r
b8786489 628 DEBUG ((DEBUG_INFO, "AuthenticatedImage - 0x%x - 0x%x\n", *AuthenticatedImage, *AuthenticatedImageSize));\r
e29caef2 629\r
b8786489 630 Result = ExtractSystemFirmwareImage (*AuthenticatedImage, *AuthenticatedImageSize, &SystemFirmwareImage, &SystemFirmwareImageSize);\r
e29caef2
JY
631 if (!Result) {\r
632 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
b8786489 633 DEBUG ((DEBUG_INFO, "ExtractSystemFirmwareImage - fail\n"));\r
e29caef2
JY
634 return EFI_SECURITY_VIOLATION;\r
635 }\r
e29caef2 636\r
b8786489
MK
637 DEBUG ((DEBUG_INFO, "SystemFirmwareImage - 0x%x - 0x%x\n", SystemFirmwareImage, SystemFirmwareImageSize));\r
638\r
639 Result = ExtractSystemFirmwareImageFmpInfo (SystemFirmwareImage, SystemFirmwareImageSize, &ImageFmpInfo, &ImageFmpInfoSize);\r
e29caef2
JY
640 if (!Result) {\r
641 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
b8786489 642 DEBUG ((DEBUG_INFO, "ExtractSystemFirmwareImageFmpInfo - fail\n"));\r
e29caef2
JY
643 return EFI_SECURITY_VIOLATION;\r
644 }\r
645\r
646 *LastAttemptVersion = ImageFmpInfo->Version;\r
b8786489
MK
647 DEBUG ((DEBUG_INFO, "ImageFmpInfo - 0x%x - 0x%x\n", ImageFmpInfo, ImageFmpInfoSize));\r
648 DEBUG ((DEBUG_INFO, "NewImage Version - 0x%x\n", ImageFmpInfo->Version));\r
649 DEBUG ((DEBUG_INFO, "NewImage LowestSupportedImageVersion - 0x%x\n", ImageFmpInfo->LowestSupportedImageVersion));\r
e29caef2 650\r
b8786489 651 CurrentImageFmpInfo = mImageFmpInfo;\r
e29caef2
JY
652 CurrentImageFmpInfoSize = mImageFmpInfoSize;\r
653\r
b8786489
MK
654 DEBUG ((DEBUG_INFO, "ImageFmpInfo - 0x%x - 0x%x\n", CurrentImageFmpInfo, CurrentImageFmpInfoSize));\r
655 DEBUG ((DEBUG_INFO, "Current Version - 0x%x\n", CurrentImageFmpInfo->Version));\r
656 DEBUG ((DEBUG_INFO, "Current LowestSupportedImageVersion - 0x%x\n", CurrentImageFmpInfo->LowestSupportedImageVersion));\r
e29caef2
JY
657\r
658 if (ForceVersionMatch) {\r
659 if (CurrentImageFmpInfo->Version != ImageFmpInfo->Version) {\r
660 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;\r
b8786489 661 DEBUG ((DEBUG_INFO, "ForceVersionMatch check - fail\n"));\r
e29caef2
JY
662 return EFI_SECURITY_VIOLATION;\r
663 }\r
664 } else {\r
41ccec58 665 if (ImageFmpInfo->Version < CurrentImageFmpInfo->LowestSupportedImageVersion) {\r
e29caef2 666 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;\r
b8786489 667 DEBUG ((DEBUG_INFO, "LowestSupportedImageVersion check - fail\n"));\r
e29caef2
JY
668 return EFI_SECURITY_VIOLATION;\r
669 }\r
670 }\r
671\r
672 *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
673 return EFI_SUCCESS;\r
674}\r
675\r
01ee04c4
LG
676/**\r
677 PcdCallBack gets the real set PCD value\r
678\r
679 @param[in] CallBackGuid The PCD token GUID being set.\r
680 @param[in] CallBackToken The PCD token number being set.\r
681 @param[in, out] TokenData A pointer to the token data being set.\r
682 @param[in] TokenDataSize The size, in bytes, of the data being set.\r
683\r
684**/\r
685VOID\r
686EFIAPI\r
687EdkiiSystemCapsuleLibPcdCallBack (\r
b8786489
MK
688 IN CONST GUID *CallBackGuid OPTIONAL,\r
689 IN UINTN CallBackToken,\r
690 IN OUT VOID *TokenData,\r
691 IN UINTN TokenDataSize\r
01ee04c4
LG
692 )\r
693{\r
694 if (CompareGuid (CallBackGuid, &gEfiSignedCapsulePkgTokenSpaceGuid) &&\r
b8786489
MK
695 (CallBackToken == PcdToken (PcdEdkiiSystemFirmwareImageDescriptor)))\r
696 {\r
01ee04c4 697 mImageFmpInfoSize = TokenDataSize;\r
b8786489
MK
698 mImageFmpInfo = AllocateCopyPool (mImageFmpInfoSize, TokenData);\r
699 ASSERT (mImageFmpInfo != NULL);\r
01ee04c4
LG
700 //\r
701 // Cancel Callback after get the real set value\r
702 //\r
703 LibPcdCancelCallback (\r
704 &gEfiSignedCapsulePkgTokenSpaceGuid,\r
705 PcdToken (PcdEdkiiSystemFirmwareImageDescriptor),\r
706 EdkiiSystemCapsuleLibPcdCallBack\r
707 );\r
708 }\r
709\r
710 if (CompareGuid (CallBackGuid, &gEfiSignedCapsulePkgTokenSpaceGuid) &&\r
b8786489
MK
711 (CallBackToken == PcdToken (PcdEdkiiSystemFirmwareFileGuid)))\r
712 {\r
713 CopyGuid (&mEdkiiSystemFirmwareFileGuid, TokenData);\r
01ee04c4
LG
714 //\r
715 // Cancel Callback after get the real set value\r
716 //\r
717 LibPcdCancelCallback (\r
718 &gEfiSignedCapsulePkgTokenSpaceGuid,\r
719 PcdToken (PcdEdkiiSystemFirmwareFileGuid),\r
720 EdkiiSystemCapsuleLibPcdCallBack\r
721 );\r
722 }\r
723}\r
724\r
e29caef2
JY
725/**\r
726 The constructor function.\r
727\r
728 @retval EFI_SUCCESS The constructor successfully .\r
729**/\r
730EFI_STATUS\r
731EFIAPI\r
732EdkiiSystemCapsuleLibConstructor (\r
733 VOID\r
734 )\r
735{\r
b8786489
MK
736 mImageFmpInfoSize = PcdGetSize (PcdEdkiiSystemFirmwareImageDescriptor);\r
737 mImageFmpInfo = PcdGetPtr (PcdEdkiiSystemFirmwareImageDescriptor);\r
01ee04c4
LG
738 //\r
739 // Verify Firmware Image Descriptor first\r
740 //\r
b8786489
MK
741 if ((mImageFmpInfoSize < sizeof (EDKII_SYSTEM_FIRMWARE_IMAGE_DESCRIPTOR)) ||\r
742 (mImageFmpInfo->Signature != EDKII_SYSTEM_FIRMWARE_IMAGE_DESCRIPTOR_SIGNATURE))\r
743 {\r
01ee04c4
LG
744 //\r
745 // SystemFirmwareImageDescriptor is not set.\r
746 // Register PCD set callback to hook PCD value set.\r
747 //\r
748 mImageFmpInfo = NULL;\r
749 mImageFmpInfoSize = 0;\r
750 LibPcdCallbackOnSet (\r
751 &gEfiSignedCapsulePkgTokenSpaceGuid,\r
752 PcdToken (PcdEdkiiSystemFirmwareImageDescriptor),\r
753 EdkiiSystemCapsuleLibPcdCallBack\r
754 );\r
755 } else {\r
756 mImageFmpInfo = AllocateCopyPool (mImageFmpInfoSize, mImageFmpInfo);\r
b8786489 757 ASSERT (mImageFmpInfo != NULL);\r
01ee04c4
LG
758 }\r
759\r
b8786489 760 CopyGuid (&mEdkiiSystemFirmwareFileGuid, PcdGetPtr (PcdEdkiiSystemFirmwareFileGuid));\r
01ee04c4
LG
761 //\r
762 // Verify GUID value first\r
763 //\r
764 if (CompareGuid (&mEdkiiSystemFirmwareFileGuid, &gZeroGuid)) {\r
765 LibPcdCallbackOnSet (\r
766 &gEfiSignedCapsulePkgTokenSpaceGuid,\r
767 PcdToken (PcdEdkiiSystemFirmwareFileGuid),\r
768 EdkiiSystemCapsuleLibPcdCallBack\r
769 );\r
770 }\r
b8786489 771\r
e29caef2
JY
772 return EFI_SUCCESS;\r
773}\r