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