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