Home | History | Annotate | Download | only in EdkiiSystemCapsuleLib
      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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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