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