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