SignedCapsulePkg: Update EdkiiSystemCapsuleLib to check PCD value
[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
ce5354d6 9 Copyright (c) 2016 - 2017, 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
191 DEBUG((DEBUG_ERROR, "checking FV....0x%08x - 0x%x\n", FvHeader, FvHeader->FvLength));\r
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
228 //\r
229 // Check section\r
230 //\r
231 *OutFfsBuffer = FfsHeader;\r
232 *OutFfsBufferSize = FfsSize;\r
233 return TRUE;\r
234 } else {\r
235 //\r
236 // Any other type is not allowed\r
237 //\r
238 DEBUG((DEBUG_INFO, "GetFfsByName - other FFS type 0x%x, name %g\n", FfsHeader->Type, &FfsHeader->Name));\r
239 }\r
240\r
241 //\r
242 // Next File\r
243 //\r
244 FfsHeader = (EFI_FFS_FILE_HEADER *)((UINTN)FfsHeader + ALIGN_VALUE(FfsSize, 8));\r
245 }\r
246\r
247 //\r
248 // Next FV\r
249 //\r
250 FvHeader = (VOID *)(UINTN)((UINTN)FvHeader + FvHeader->FvLength);\r
251 DEBUG((DEBUG_ERROR, "Next FV....0x%08x - 0x%x\n", FvHeader, FvHeader->FvLength));\r
252 }\r
253\r
254 if (!FvFound) {\r
255 DEBUG((DEBUG_ERROR, "GetFfsByName - NO FV Found\n"));\r
256 }\r
257 return FALSE;\r
258}\r
259\r
260/**\r
261 Extract the driver FV from an authenticated image.\r
262\r
263 @param[in] AuthenticatedImage The authenticated capsule image.\r
264 @param[in] AuthenticatedImageSize The size of the authenticated capsule image in bytes.\r
265 @param[out] DriverFvImage The driver FV image.\r
266 @param[out] DriverFvImageSize The size of the driver FV image in bytes.\r
267\r
268 @retval TRUE The driver Fv is extracted.\r
269 @retval FALSE The driver Fv is not extracted.\r
270**/\r
271BOOLEAN\r
272EFIAPI\r
273ExtractDriverFvImage (\r
274 IN VOID *AuthenticatedImage,\r
275 IN UINTN AuthenticatedImageSize,\r
276 OUT VOID **DriverFvImage,\r
277 OUT UINTN *DriverFvImageSize\r
278 )\r
279{\r
280 BOOLEAN Result;\r
281 UINT32 FileHeaderSize;\r
282\r
283 *DriverFvImage = NULL;\r
284 *DriverFvImageSize = 0;\r
285\r
286 Result = GetFfsByName(AuthenticatedImage, AuthenticatedImageSize, &gEdkiiSystemFmpCapsuleDriverFvFileGuid, EFI_FV_FILETYPE_RAW, DriverFvImage, DriverFvImageSize);\r
287 if (!Result) {\r
288 return FALSE;\r
289 }\r
290\r
291 if (IS_FFS_FILE2(*DriverFvImage)) {\r
292 FileHeaderSize = sizeof(EFI_FFS_FILE_HEADER2);\r
293 } else {\r
294 FileHeaderSize = sizeof(EFI_FFS_FILE_HEADER);\r
295 }\r
296 *DriverFvImage = (UINT8 *)*DriverFvImage + FileHeaderSize;\r
297 *DriverFvImageSize = *DriverFvImageSize - FileHeaderSize;\r
298\r
299 return Result;\r
300}\r
301\r
302/**\r
303 Extract the config image from an authenticated image.\r
304\r
305 @param[in] AuthenticatedImage The authenticated capsule image.\r
306 @param[in] AuthenticatedImageSize The size of the authenticated capsule image in bytes.\r
307 @param[out] ConfigImage The config image.\r
308 @param[out] ConfigImageSize The size of the config image in bytes.\r
309\r
310 @retval TRUE The config image is extracted.\r
311 @retval FALSE The config image is not extracted.\r
312**/\r
313BOOLEAN\r
314EFIAPI\r
315ExtractConfigImage (\r
316 IN VOID *AuthenticatedImage,\r
317 IN UINTN AuthenticatedImageSize,\r
318 OUT VOID **ConfigImage,\r
319 OUT UINTN *ConfigImageSize\r
320 )\r
321{\r
322 BOOLEAN Result;\r
323 UINT32 FileHeaderSize;\r
324\r
325 *ConfigImage = NULL;\r
326 *ConfigImageSize = 0;\r
327\r
328 Result = GetFfsByName(AuthenticatedImage, AuthenticatedImageSize, &gEdkiiSystemFmpCapsuleConfigFileGuid, EFI_FV_FILETYPE_RAW, ConfigImage, ConfigImageSize);\r
329 if (!Result) {\r
330 return FALSE;\r
331 }\r
332\r
333 if (IS_FFS_FILE2(*ConfigImage)) {\r
334 FileHeaderSize = sizeof(EFI_FFS_FILE_HEADER2);\r
335 } else {\r
336 FileHeaderSize = sizeof(EFI_FFS_FILE_HEADER);\r
337 }\r
338 *ConfigImage = (UINT8 *)*ConfigImage + FileHeaderSize;\r
339 *ConfigImageSize = *ConfigImageSize - FileHeaderSize;\r
340\r
341 return Result;\r
342}\r
343\r
344/**\r
345 Extract the authenticated image from an FMP capsule image.\r
346\r
347 Caution: This function may receive untrusted input.\r
348\r
349 @param[in] Image The FMP capsule image, including EFI_FIRMWARE_IMAGE_AUTHENTICATION.\r
350 @param[in] ImageSize The size of FMP capsule image in bytes.\r
351 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
352 @param[out] AuthenticatedImage The authenticated capsule image, excluding EFI_FIRMWARE_IMAGE_AUTHENTICATION.\r
353 @param[out] AuthenticatedImageSize The size of the authenticated capsule image in bytes.\r
354\r
355 @retval TRUE The authenticated image is extracted.\r
356 @retval FALSE The authenticated image is not extracted.\r
357**/\r
358BOOLEAN\r
359EFIAPI\r
360ExtractAuthenticatedImage (\r
361 IN VOID *Image,\r
362 IN UINTN ImageSize,\r
363 OUT UINT32 *LastAttemptStatus,\r
364 OUT VOID **AuthenticatedImage,\r
365 OUT UINTN *AuthenticatedImageSize\r
366 )\r
367{\r
368 EFI_FIRMWARE_IMAGE_AUTHENTICATION *ImageAuth;\r
369 EFI_STATUS Status;\r
370 GUID *CertType;\r
371 VOID *PublicKeyData;\r
372 UINTN PublicKeyDataLength;\r
373\r
374 DEBUG((DEBUG_INFO, "ExtractAuthenticatedImage - Image: 0x%08x - 0x%08x\n", (UINTN)Image, (UINTN)ImageSize));\r
375\r
376 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
377 if ((Image == NULL) || (ImageSize == 0)) {\r
378 return FALSE;\r
379 }\r
380\r
381 ImageAuth = (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image;\r
382 if (ImageSize < sizeof(EFI_FIRMWARE_IMAGE_AUTHENTICATION)) {\r
383 DEBUG((DEBUG_ERROR, "ExtractAuthenticatedImage - ImageSize too small\n"));\r
384 return FALSE;\r
385 }\r
386 if (ImageAuth->AuthInfo.Hdr.dwLength <= OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData)) {\r
387 DEBUG((DEBUG_ERROR, "ExtractAuthenticatedImage - dwLength too small\n"));\r
388 return FALSE;\r
389 }\r
ce5354d6 390 if ((UINTN) ImageAuth->AuthInfo.Hdr.dwLength > MAX_UINTN - sizeof(UINT64)) {\r
e29caef2
JY
391 DEBUG((DEBUG_ERROR, "ExtractAuthenticatedImage - dwLength too big\n"));\r
392 return FALSE;\r
393 }\r
394 if (ImageSize <= sizeof(ImageAuth->MonotonicCount) + ImageAuth->AuthInfo.Hdr.dwLength) {\r
395 DEBUG((DEBUG_ERROR, "ExtractAuthenticatedImage - ImageSize too small\n"));\r
396 return FALSE;\r
397 }\r
398 if (ImageAuth->AuthInfo.Hdr.wRevision != 0x0200) {\r
399 DEBUG((DEBUG_ERROR, "ExtractAuthenticatedImage - wRevision: 0x%02x, expect - 0x%02x\n", (UINTN)ImageAuth->AuthInfo.Hdr.wRevision, (UINTN)0x0200));\r
400 return FALSE;\r
401 }\r
402 if (ImageAuth->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) {\r
403 DEBUG((DEBUG_ERROR, "ExtractAuthenticatedImage - wCertificateType: 0x%02x, expect - 0x%02x\n", (UINTN)ImageAuth->AuthInfo.Hdr.wCertificateType, (UINTN)WIN_CERT_TYPE_EFI_GUID));\r
404 return FALSE;\r
405 }\r
406\r
407 CertType = &ImageAuth->AuthInfo.CertType;\r
408 DEBUG((DEBUG_INFO, "ExtractAuthenticatedImage - CertType: %g\n", CertType));\r
409\r
410 if (CompareGuid(&gEfiCertPkcs7Guid, CertType)) {\r
411 PublicKeyData = PcdGetPtr(PcdPkcs7CertBuffer);\r
412 PublicKeyDataLength = PcdGetSize(PcdPkcs7CertBuffer);\r
413 } else if (CompareGuid(&gEfiCertTypeRsa2048Sha256Guid, CertType)) {\r
414 PublicKeyData = PcdGetPtr(PcdRsa2048Sha256PublicKeyBuffer);\r
415 PublicKeyDataLength = PcdGetSize(PcdRsa2048Sha256PublicKeyBuffer);\r
416 } else {\r
417 return FALSE;\r
418 }\r
7e6e4f96
JY
419 ASSERT (PublicKeyData != NULL);\r
420 ASSERT (PublicKeyDataLength != 0);\r
e29caef2
JY
421\r
422 Status = AuthenticateFmpImage(\r
423 ImageAuth,\r
424 ImageSize,\r
425 PublicKeyData,\r
426 PublicKeyDataLength\r
427 );\r
428 switch (Status) {\r
429 case RETURN_SUCCESS:\r
430 *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
431 break;\r
432 case RETURN_SECURITY_VIOLATION:\r
433 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR;\r
434 break;\r
435 case RETURN_INVALID_PARAMETER:\r
436 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
437 break;\r
438 case RETURN_UNSUPPORTED:\r
439 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
440 break;\r
441 case RETURN_OUT_OF_RESOURCES:\r
442 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
443 break;\r
444 default:\r
445 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
446 break;\r
447 }\r
448 if (EFI_ERROR(Status)) {\r
449 return FALSE;\r
450 }\r
451\r
452 if (AuthenticatedImage != NULL) {\r
453 *AuthenticatedImage = (UINT8 *)ImageAuth + ImageAuth->AuthInfo.Hdr.dwLength + sizeof(ImageAuth->MonotonicCount);\r
454 }\r
455 if (AuthenticatedImageSize != NULL) {\r
456 *AuthenticatedImageSize = ImageSize - ImageAuth->AuthInfo.Hdr.dwLength - sizeof(ImageAuth->MonotonicCount);\r
457 }\r
458 return TRUE;\r
459}\r
460\r
461/**\r
462 Extract ImageFmpInfo from system firmware.\r
463\r
464 @param[in] SystemFirmwareImage The System Firmware image.\r
465 @param[in] SystemFirmwareImageSize The size of the System Firmware image in bytes.\r
466 @param[out] ImageFmpInfo The ImageFmpInfo.\r
467 @param[out] ImageFmpInfoSize The size of the ImageFmpInfo in bytes.\r
468\r
469 @retval TRUE The ImageFmpInfo is extracted.\r
470 @retval FALSE The ImageFmpInfo is not extracted.\r
471**/\r
472BOOLEAN\r
473EFIAPI\r
474ExtractSystemFirmwareImageFmpInfo (\r
475 IN VOID *SystemFirmwareImage,\r
476 IN UINTN SystemFirmwareImageSize,\r
477 OUT EDKII_SYSTEM_FIRMWARE_IMAGE_DESCRIPTOR **ImageFmpInfo,\r
478 OUT UINTN *ImageFmpInfoSize\r
479 )\r
480{\r
481 BOOLEAN Result;\r
482 UINT32 SectionHeaderSize;\r
483 UINT32 FileHeaderSize;\r
484\r
485 *ImageFmpInfo = NULL;\r
486 *ImageFmpInfoSize = 0;\r
487\r
488 Result = GetFfsByName(SystemFirmwareImage, SystemFirmwareImageSize, &gEdkiiSystemFirmwareImageDescriptorFileGuid, EFI_FV_FILETYPE_ALL, (VOID **)ImageFmpInfo, ImageFmpInfoSize);\r
489 if (!Result) {\r
490 return FALSE;\r
491 }\r
492 if (IS_FFS_FILE2 (*ImageFmpInfo)) {\r
493 FileHeaderSize = sizeof(EFI_FFS_FILE_HEADER2);\r
494 } else {\r
495 FileHeaderSize = sizeof(EFI_FFS_FILE_HEADER);\r
496 }\r
497 *ImageFmpInfo = (VOID *)((UINT8 *)*ImageFmpInfo + FileHeaderSize);\r
498 *ImageFmpInfoSize = *ImageFmpInfoSize - FileHeaderSize;\r
499\r
500 Result = GetSectionByType(*ImageFmpInfo, (UINT32)*ImageFmpInfoSize, EFI_SECTION_RAW, 0, (VOID **)ImageFmpInfo, ImageFmpInfoSize);\r
501 if (!Result) {\r
502 return FALSE;\r
503 }\r
504 if (IS_SECTION2(*ImageFmpInfo)) {\r
505 SectionHeaderSize = sizeof(EFI_RAW_SECTION2);\r
506 } else {\r
507 SectionHeaderSize = sizeof(EFI_RAW_SECTION);\r
508 }\r
509 *ImageFmpInfo = (VOID *)((UINT8 *)*ImageFmpInfo + SectionHeaderSize);\r
510 *ImageFmpInfoSize = *ImageFmpInfoSize - SectionHeaderSize;\r
511\r
512 return TRUE;\r
513}\r
514\r
515/**\r
516 Extract the System Firmware image from an authenticated image.\r
517\r
518 @param[in] AuthenticatedImage The authenticated capsule image.\r
519 @param[in] AuthenticatedImageSize The size of the authenticated capsule image in bytes.\r
520 @param[out] SystemFirmwareImage The System Firmware image.\r
521 @param[out] SystemFirmwareImageSize The size of the System Firmware image in bytes.\r
522\r
523 @retval TRUE The System Firmware image is extracted.\r
524 @retval FALSE The System Firmware image is not extracted.\r
525**/\r
526BOOLEAN\r
527EFIAPI\r
528ExtractSystemFirmwareImage (\r
529 IN VOID *AuthenticatedImage,\r
530 IN UINTN AuthenticatedImageSize,\r
531 OUT VOID **SystemFirmwareImage,\r
532 OUT UINTN *SystemFirmwareImageSize\r
533 )\r
534{\r
535 BOOLEAN Result;\r
536 UINT32 FileHeaderSize;\r
537\r
538 *SystemFirmwareImage = NULL;\r
539 *SystemFirmwareImageSize = 0;\r
540\r
541 Result = GetFfsByName(AuthenticatedImage, AuthenticatedImageSize, &mEdkiiSystemFirmwareFileGuid, EFI_FV_FILETYPE_RAW, SystemFirmwareImage, SystemFirmwareImageSize);\r
542 if (!Result) {\r
543 // no nested FV, just return all data.\r
544 *SystemFirmwareImage = AuthenticatedImage;\r
545 *SystemFirmwareImageSize = AuthenticatedImageSize;\r
546\r
547 return TRUE;\r
548 }\r
549 if (IS_FFS_FILE2 (*SystemFirmwareImage)) {\r
550 FileHeaderSize = sizeof(EFI_FFS_FILE_HEADER2);\r
551 } else {\r
552 FileHeaderSize = sizeof(EFI_FFS_FILE_HEADER);\r
553 }\r
554 *SystemFirmwareImage = (UINT8 *)*SystemFirmwareImage + FileHeaderSize;\r
555 *SystemFirmwareImageSize = *SystemFirmwareImageSize - FileHeaderSize;\r
556\r
557 return Result;\r
558}\r
559\r
560/**\r
561 Authenticated system firmware FMP capsule image.\r
562\r
563 Caution: This function may receive untrusted input.\r
564\r
565 @param[in] Image The FMP capsule image, including EFI_FIRMWARE_IMAGE_AUTHENTICATION.\r
566 @param[in] ImageSize The size of FMP capsule image in bytes.\r
567 @param[in] ForceVersionMatch TRUE: The version of capsule must be as same as the version of current image.\r
568 FALSE: The version of capsule must be as same as greater than the lowest\r
569 supported version of current image.\r
570 @param[out] LastAttemptVersion The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
571 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
572 @param[out] AuthenticatedImage The authenticated capsule image, excluding EFI_FIRMWARE_IMAGE_AUTHENTICATION.\r
573 @param[out] AuthenticatedImageSize The size of the authenticated capsule image in bytes.\r
574\r
575 @retval TRUE Authentication passes and the authenticated image is extracted.\r
576 @retval FALSE Authentication fails and the authenticated image is not extracted.\r
577**/\r
578EFI_STATUS\r
579EFIAPI\r
580CapsuleAuthenticateSystemFirmware (\r
581 IN VOID *Image,\r
582 IN UINTN ImageSize,\r
583 IN BOOLEAN ForceVersionMatch,\r
584 OUT UINT32 *LastAttemptVersion,\r
585 OUT UINT32 *LastAttemptStatus,\r
586 OUT VOID **AuthenticatedImage,\r
587 OUT UINTN *AuthenticatedImageSize\r
588 )\r
589{\r
590 BOOLEAN Result;\r
591 EDKII_SYSTEM_FIRMWARE_IMAGE_DESCRIPTOR *ImageFmpInfo;\r
592 UINTN ImageFmpInfoSize;\r
593 EDKII_SYSTEM_FIRMWARE_IMAGE_DESCRIPTOR *CurrentImageFmpInfo;\r
594 UINTN CurrentImageFmpInfoSize;\r
595 VOID *SystemFirmwareImage;\r
596 UINTN SystemFirmwareImageSize;\r
597\r
598 *LastAttemptVersion = 0;\r
599\r
600 //\r
601 // NOTE: This function need run in an isolated environment.\r
602 // Do not touch FMP protocol and its private structure.\r
603 //\r
01ee04c4
LG
604 if (mImageFmpInfo == NULL) {\r
605 DEBUG((DEBUG_INFO, "ImageFmpInfo is not set\n"));\r
606 return EFI_SECURITY_VIOLATION;\r
607 }\r
e29caef2
JY
608\r
609 Result = ExtractAuthenticatedImage((VOID *)Image, ImageSize, LastAttemptStatus, AuthenticatedImage, AuthenticatedImageSize);\r
610 if (!Result) {\r
611 DEBUG((DEBUG_INFO, "ExtractAuthenticatedImage - fail\n"));\r
612 return EFI_SECURITY_VIOLATION;\r
613 }\r
614\r
615 DEBUG((DEBUG_INFO, "AuthenticatedImage - 0x%x - 0x%x\n", *AuthenticatedImage, *AuthenticatedImageSize));\r
616\r
617 Result = ExtractSystemFirmwareImage(*AuthenticatedImage, *AuthenticatedImageSize, &SystemFirmwareImage, &SystemFirmwareImageSize);\r
618 if (!Result) {\r
619 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
620 DEBUG((DEBUG_INFO, "ExtractSystemFirmwareImage - fail\n"));\r
621 return EFI_SECURITY_VIOLATION;\r
622 }\r
623 DEBUG((DEBUG_INFO, "SystemFirmwareImage - 0x%x - 0x%x\n", SystemFirmwareImage, SystemFirmwareImageSize));\r
624\r
625 Result = ExtractSystemFirmwareImageFmpInfo(SystemFirmwareImage, SystemFirmwareImageSize, &ImageFmpInfo, &ImageFmpInfoSize);\r
626 if (!Result) {\r
627 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
628 DEBUG((DEBUG_INFO, "ExtractSystemFirmwareImageFmpInfo - fail\n"));\r
629 return EFI_SECURITY_VIOLATION;\r
630 }\r
631\r
632 *LastAttemptVersion = ImageFmpInfo->Version;\r
633 DEBUG((DEBUG_INFO, "ImageFmpInfo - 0x%x - 0x%x\n", ImageFmpInfo, ImageFmpInfoSize));\r
634 DEBUG((DEBUG_INFO, "NewImage Version - 0x%x\n", ImageFmpInfo->Version));\r
635 DEBUG((DEBUG_INFO, "NewImage LowestSupportedImageVersion - 0x%x\n", ImageFmpInfo->LowestSupportedImageVersion));\r
636\r
637 CurrentImageFmpInfo = mImageFmpInfo;\r
638 CurrentImageFmpInfoSize = mImageFmpInfoSize;\r
639\r
640 DEBUG((DEBUG_INFO, "ImageFmpInfo - 0x%x - 0x%x\n", CurrentImageFmpInfo, CurrentImageFmpInfoSize));\r
641 DEBUG((DEBUG_INFO, "Current Version - 0x%x\n", CurrentImageFmpInfo->Version));\r
642 DEBUG((DEBUG_INFO, "Current LowestSupportedImageVersion - 0x%x\n", CurrentImageFmpInfo->LowestSupportedImageVersion));\r
643\r
644 if (ForceVersionMatch) {\r
645 if (CurrentImageFmpInfo->Version != ImageFmpInfo->Version) {\r
646 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;\r
647 DEBUG((DEBUG_INFO, "ForceVersionMatch check - fail\n"));\r
648 return EFI_SECURITY_VIOLATION;\r
649 }\r
650 } else {\r
41ccec58 651 if (ImageFmpInfo->Version < CurrentImageFmpInfo->LowestSupportedImageVersion) {\r
e29caef2
JY
652 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;\r
653 DEBUG((DEBUG_INFO, "LowestSupportedImageVersion check - fail\n"));\r
654 return EFI_SECURITY_VIOLATION;\r
655 }\r
656 }\r
657\r
658 *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
659 return EFI_SUCCESS;\r
660}\r
661\r
01ee04c4
LG
662/**\r
663 PcdCallBack gets the real set PCD value\r
664\r
665 @param[in] CallBackGuid The PCD token GUID being set.\r
666 @param[in] CallBackToken The PCD token number being set.\r
667 @param[in, out] TokenData A pointer to the token data being set.\r
668 @param[in] TokenDataSize The size, in bytes, of the data being set.\r
669\r
670**/\r
671VOID\r
672EFIAPI\r
673EdkiiSystemCapsuleLibPcdCallBack (\r
674 IN CONST GUID *CallBackGuid, OPTIONAL\r
675 IN UINTN CallBackToken,\r
676 IN OUT VOID *TokenData,\r
677 IN UINTN TokenDataSize\r
678 )\r
679{\r
680 if (CompareGuid (CallBackGuid, &gEfiSignedCapsulePkgTokenSpaceGuid) &&\r
681 CallBackToken == PcdToken (PcdEdkiiSystemFirmwareImageDescriptor)) {\r
682 mImageFmpInfoSize = TokenDataSize;\r
683 mImageFmpInfo = AllocateCopyPool (mImageFmpInfoSize, TokenData);\r
684 ASSERT(mImageFmpInfo != NULL);\r
685 //\r
686 // Cancel Callback after get the real set value\r
687 //\r
688 LibPcdCancelCallback (\r
689 &gEfiSignedCapsulePkgTokenSpaceGuid,\r
690 PcdToken (PcdEdkiiSystemFirmwareImageDescriptor),\r
691 EdkiiSystemCapsuleLibPcdCallBack\r
692 );\r
693 }\r
694\r
695 if (CompareGuid (CallBackGuid, &gEfiSignedCapsulePkgTokenSpaceGuid) &&\r
696 CallBackToken == PcdToken (PcdEdkiiSystemFirmwareFileGuid)) {\r
697 CopyGuid(&mEdkiiSystemFirmwareFileGuid, TokenData);\r
698 //\r
699 // Cancel Callback after get the real set value\r
700 //\r
701 LibPcdCancelCallback (\r
702 &gEfiSignedCapsulePkgTokenSpaceGuid,\r
703 PcdToken (PcdEdkiiSystemFirmwareFileGuid),\r
704 EdkiiSystemCapsuleLibPcdCallBack\r
705 );\r
706 }\r
707}\r
708\r
e29caef2
JY
709/**\r
710 The constructor function.\r
711\r
712 @retval EFI_SUCCESS The constructor successfully .\r
713**/\r
714EFI_STATUS\r
715EFIAPI\r
716EdkiiSystemCapsuleLibConstructor (\r
717 VOID\r
718 )\r
719{\r
720 mImageFmpInfoSize = PcdGetSize(PcdEdkiiSystemFirmwareImageDescriptor);\r
01ee04c4
LG
721 mImageFmpInfo = PcdGetPtr(PcdEdkiiSystemFirmwareImageDescriptor);\r
722 //\r
723 // Verify Firmware Image Descriptor first\r
724 //\r
725 if (mImageFmpInfoSize < sizeof (EDKII_SYSTEM_FIRMWARE_IMAGE_DESCRIPTOR) ||\r
726 mImageFmpInfo->Signature != EDKII_SYSTEM_FIRMWARE_IMAGE_DESCRIPTOR_SIGNATURE) {\r
727 //\r
728 // SystemFirmwareImageDescriptor is not set.\r
729 // Register PCD set callback to hook PCD value set.\r
730 //\r
731 mImageFmpInfo = NULL;\r
732 mImageFmpInfoSize = 0;\r
733 LibPcdCallbackOnSet (\r
734 &gEfiSignedCapsulePkgTokenSpaceGuid,\r
735 PcdToken (PcdEdkiiSystemFirmwareImageDescriptor),\r
736 EdkiiSystemCapsuleLibPcdCallBack\r
737 );\r
738 } else {\r
739 mImageFmpInfo = AllocateCopyPool (mImageFmpInfoSize, mImageFmpInfo);\r
740 ASSERT(mImageFmpInfo != NULL);\r
741 }\r
742\r
e29caef2 743 CopyGuid(&mEdkiiSystemFirmwareFileGuid, PcdGetPtr(PcdEdkiiSystemFirmwareFileGuid));\r
01ee04c4
LG
744 //\r
745 // Verify GUID value first\r
746 //\r
747 if (CompareGuid (&mEdkiiSystemFirmwareFileGuid, &gZeroGuid)) {\r
748 LibPcdCallbackOnSet (\r
749 &gEfiSignedCapsulePkgTokenSpaceGuid,\r
750 PcdToken (PcdEdkiiSystemFirmwareFileGuid),\r
751 EdkiiSystemCapsuleLibPcdCallBack\r
752 );\r
753 }\r
e29caef2
JY
754 return EFI_SUCCESS;\r
755}\r