Home | History | Annotate | Download | only in PeiRsa2048Sha256GuidedSectionExtractLib
      1 /** @file
      2 
      3   This library registers RSA 2048 SHA 256 guided section handler
      4   to parse RSA 2048 SHA 256 encapsulation section and extract raw data.
      5   It uses the BaseCrypyLib based on OpenSSL to authenticate the signature.
      6 
      7 Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
      8 This program and the accompanying materials
      9 are licensed and made available under the terms and conditions of the BSD License
     10 which accompanies this distribution.  The full text of the license may be found at
     11 http://opensource.org/licenses/bsd-license.php
     12 
     13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     15 
     16 **/
     17 
     18 #include <PiPei.h>
     19 #include <Protocol/Hash.h>
     20 #include <Library/ExtractGuidedSectionLib.h>
     21 #include <Library/DebugLib.h>
     22 #include <Library/BaseMemoryLib.h>
     23 #include <Library/MemoryAllocationLib.h>
     24 #include <Library/PcdLib.h>
     25 #include <Guid/WinCertificate.h>
     26 #include <Library/BaseCryptLib.h>
     27 #include <Library/PerformanceLib.h>
     28 #include <Guid/SecurityPkgTokenSpace.h>
     29 
     30 ///
     31 /// RSA 2048 SHA 256 Guided Section header
     32 ///
     33 typedef struct {
     34   EFI_GUID_DEFINED_SECTION        GuidedSectionHeader;     ///< EFI guided section header
     35   EFI_CERT_BLOCK_RSA_2048_SHA256  CertBlockRsa2048Sha256;  ///< RSA 2048-bit Signature
     36 } RSA_2048_SHA_256_SECTION_HEADER;
     37 
     38 typedef struct {
     39   EFI_GUID_DEFINED_SECTION2       GuidedSectionHeader;     ///< EFI guided section header
     40   EFI_CERT_BLOCK_RSA_2048_SHA256  CertBlockRsa2048Sha256;  ///< RSA 2048-bit Signature
     41 } RSA_2048_SHA_256_SECTION2_HEADER;
     42 
     43 ///
     44 /// Public Exponent of RSA Key.
     45 ///
     46 CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };
     47 
     48 /**
     49 
     50   GetInfo gets raw data size and attribute of the input guided section.
     51   It first checks whether the input guid section is supported.
     52   If not, EFI_INVALID_PARAMETER will return.
     53 
     54   @param InputSection       Buffer containing the input GUIDed section to be processed.
     55   @param OutputBufferSize   The size of OutputBuffer.
     56   @param ScratchBufferSize  The size of ScratchBuffer.
     57   @param SectionAttribute   The attribute of the input guided section.
     58 
     59   @retval EFI_SUCCESS            The size of destination buffer, the size of scratch buffer and
     60                                  the attribute of the input section are successfully retrieved.
     61   @retval EFI_INVALID_PARAMETER  The GUID in InputSection does not match this instance guid.
     62 
     63 **/
     64 EFI_STATUS
     65 EFIAPI
     66 Rsa2048Sha256GuidedSectionGetInfo (
     67   IN  CONST VOID  *InputSection,
     68   OUT UINT32      *OutputBufferSize,
     69   OUT UINT32      *ScratchBufferSize,
     70   OUT UINT16      *SectionAttribute
     71   )
     72 {
     73   if (IS_SECTION2 (InputSection)) {
     74     //
     75     // Check whether the input guid section is recognized.
     76     //
     77     if (!CompareGuid (
     78         &gEfiCertTypeRsa2048Sha256Guid,
     79         &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) {
     80       return EFI_INVALID_PARAMETER;
     81     }
     82     //
     83     // Retrieve the size and attribute of the input section data.
     84     //
     85     *SectionAttribute  = ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->Attributes;
     86     *ScratchBufferSize = 0;
     87     *OutputBufferSize  = SECTION2_SIZE (InputSection) - sizeof(RSA_2048_SHA_256_SECTION2_HEADER);
     88   } else {
     89     //
     90     // Check whether the input guid section is recognized.
     91     //
     92     if (!CompareGuid (
     93         &gEfiCertTypeRsa2048Sha256Guid,
     94         &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {
     95       return EFI_INVALID_PARAMETER;
     96     }
     97     //
     98     // Retrieve the size and attribute of the input section data.
     99     //
    100     *SectionAttribute  = ((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes;
    101     *ScratchBufferSize = 0;
    102     *OutputBufferSize  = SECTION_SIZE (InputSection) - sizeof(RSA_2048_SHA_256_SECTION_HEADER);
    103   }
    104 
    105   return EFI_SUCCESS;
    106 }
    107 
    108 /**
    109 
    110   Extraction handler tries to extract raw data from the input guided section.
    111   It also does authentication check for RSA 2048 SHA 256 signature in the input guided section.
    112   It first checks whether the input guid section is supported.
    113   If not, EFI_INVALID_PARAMETER will return.
    114 
    115   @param InputSection    Buffer containing the input GUIDed section to be processed.
    116   @param OutputBuffer    Buffer to contain the output raw data allocated by the caller.
    117   @param ScratchBuffer   A pointer to a caller-allocated buffer for function internal use.
    118   @param AuthenticationStatus A pointer to a caller-allocated UINT32 that indicates the
    119                               authentication status of the output buffer.
    120 
    121   @retval EFI_SUCCESS            Section Data and Auth Status is extracted successfully.
    122   @retval EFI_INVALID_PARAMETER  The GUID in InputSection does not match this instance guid.
    123 
    124 **/
    125 EFI_STATUS
    126 EFIAPI
    127 Rsa2048Sha256GuidedSectionHandler (
    128   IN CONST  VOID    *InputSection,
    129   OUT       VOID    **OutputBuffer,
    130   IN        VOID    *ScratchBuffer,        OPTIONAL
    131   OUT       UINT32  *AuthenticationStatus
    132   )
    133 {
    134   EFI_STATUS                      Status;
    135   UINT32                          OutputBufferSize;
    136   EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlockRsa2048Sha256;
    137   BOOLEAN                         CryptoStatus;
    138   UINT8                           Digest[SHA256_DIGEST_SIZE];
    139   UINT8                           *PublicKey;
    140   UINTN                           PublicKeyBufferSize;
    141   VOID                            *HashContext;
    142   VOID                            *Rsa;
    143 
    144   HashContext = NULL;
    145   Rsa         = NULL;
    146 
    147   if (IS_SECTION2 (InputSection)) {
    148     //
    149     // Check whether the input guid section is recognized.
    150     //
    151     if (!CompareGuid (
    152         &gEfiCertTypeRsa2048Sha256Guid,
    153         &(((EFI_GUID_DEFINED_SECTION2 *)InputSection)->SectionDefinitionGuid))) {
    154       return EFI_INVALID_PARAMETER;
    155     }
    156 
    157     //
    158     // Get the RSA 2048 SHA 256 information.
    159     //
    160     CertBlockRsa2048Sha256 = &((RSA_2048_SHA_256_SECTION2_HEADER *) InputSection)->CertBlockRsa2048Sha256;
    161     OutputBufferSize       = SECTION2_SIZE (InputSection) - sizeof (RSA_2048_SHA_256_SECTION2_HEADER);
    162     if ((((EFI_GUID_DEFINED_SECTION *)InputSection)->Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) {
    163       PERF_START (NULL, "RsaCopy", "PEI", 0);
    164       CopyMem (*OutputBuffer, (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION2_HEADER), OutputBufferSize);
    165       PERF_END (NULL, "RsaCopy", "PEI", 0);
    166     } else {
    167       *OutputBuffer = (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION2_HEADER);
    168     }
    169 
    170     //
    171     // Implicitly RSA 2048 SHA 256 GUIDed section should have STATUS_VALID bit set
    172     //
    173     ASSERT ((((EFI_GUID_DEFINED_SECTION2 *)InputSection)->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0);
    174     *AuthenticationStatus = EFI_AUTH_STATUS_IMAGE_SIGNED;
    175   } else {
    176     //
    177     // Check whether the input guid section is recognized.
    178     //
    179     if (!CompareGuid (
    180         &gEfiCertTypeRsa2048Sha256Guid,
    181         &(((EFI_GUID_DEFINED_SECTION *)InputSection)->SectionDefinitionGuid))) {
    182       return EFI_INVALID_PARAMETER;
    183     }
    184 
    185     //
    186     // Get the RSA 2048 SHA 256 information.
    187     //
    188     CertBlockRsa2048Sha256 = &((RSA_2048_SHA_256_SECTION_HEADER *)InputSection)->CertBlockRsa2048Sha256;
    189     OutputBufferSize       = SECTION_SIZE (InputSection) - sizeof (RSA_2048_SHA_256_SECTION_HEADER);
    190     if ((((EFI_GUID_DEFINED_SECTION *)InputSection)->Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) {
    191       PERF_START (NULL, "RsaCopy", "PEI", 0);
    192       CopyMem (*OutputBuffer, (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION_HEADER), OutputBufferSize);
    193       PERF_END (NULL, "RsaCopy", "PEI", 0);
    194     } else {
    195       *OutputBuffer = (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION_HEADER);
    196     }
    197 
    198     //
    199     // Implicitly RSA 2048 SHA 256 GUIDed section should have STATUS_VALID bit set
    200     //
    201     ASSERT ((((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0);
    202     *AuthenticationStatus = EFI_AUTH_STATUS_IMAGE_SIGNED;
    203   }
    204 
    205   //
    206   // All paths from here return EFI_SUCESS and result is returned in AuthenticationStatus
    207   //
    208   Status = EFI_SUCCESS;
    209 
    210   //
    211   // Fail if the HashType is not SHA 256
    212   //
    213   if (!CompareGuid (&gEfiHashAlgorithmSha256Guid, &CertBlockRsa2048Sha256->HashType)) {
    214     DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: HASH type of section is not supported\n"));
    215     *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
    216     goto Done;
    217   }
    218 
    219   //
    220   // Allocate hash context buffer required for SHA 256
    221   //
    222   HashContext = AllocatePool (Sha256GetContextSize ());
    223   if (HashContext == NULL) {
    224     DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Can not allocate hash context\n"));
    225     *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
    226     goto Done;
    227   }
    228 
    229   //
    230   // Hash public key from data payload with SHA256.
    231   //
    232   ZeroMem (Digest, SHA256_DIGEST_SIZE);
    233   CryptoStatus = Sha256Init (HashContext);
    234   if (!CryptoStatus) {
    235     DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Sha256Init() failed\n"));
    236     *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
    237     goto Done;
    238   }
    239   CryptoStatus = Sha256Update (HashContext, &CertBlockRsa2048Sha256->PublicKey, sizeof(CertBlockRsa2048Sha256->PublicKey));
    240   if (!CryptoStatus) {
    241     DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Sha256Update() failed\n"));
    242     *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
    243     goto Done;
    244   }
    245   CryptoStatus  = Sha256Final (HashContext, Digest);
    246   if (!CryptoStatus) {
    247     DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Sha256Final() failed\n"));
    248     *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
    249     goto Done;
    250   }
    251 
    252   //
    253   // Fail if the PublicKey is not one of the public keys in PcdRsa2048Sha256PublicKeyBuffer
    254   //
    255   PublicKey = (UINT8 *)PcdGetPtr (PcdRsa2048Sha256PublicKeyBuffer);
    256   DEBUG ((DEBUG_VERBOSE, "PeiPcdRsa2048Sha256: PublicKeyBuffer = %p\n", PublicKey));
    257   ASSERT (PublicKey != NULL);
    258   DEBUG ((DEBUG_VERBOSE, "PeiPcdRsa2048Sha256: PublicKeyBuffer Token = %08x\n", PcdToken (PcdRsa2048Sha256PublicKeyBuffer)));
    259   PublicKeyBufferSize = PcdGetSize (PcdRsa2048Sha256PublicKeyBuffer);
    260   DEBUG ((DEBUG_VERBOSE, "PeiPcdRsa2048Sha256: PublicKeyBuffer Size = %08x\n", PublicKeyBufferSize));
    261   ASSERT ((PublicKeyBufferSize % SHA256_DIGEST_SIZE) == 0);
    262   CryptoStatus = FALSE;
    263   while (PublicKeyBufferSize != 0) {
    264     if (CompareMem (Digest, PublicKey, SHA256_DIGEST_SIZE) == 0) {
    265       CryptoStatus = TRUE;
    266       break;
    267     }
    268     PublicKey = PublicKey + SHA256_DIGEST_SIZE;
    269     PublicKeyBufferSize = PublicKeyBufferSize - SHA256_DIGEST_SIZE;
    270   }
    271   if (!CryptoStatus) {
    272     DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Public key in section is not supported\n"));
    273     *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
    274     goto Done;
    275   }
    276 
    277   //
    278   // Generate & Initialize RSA Context.
    279   //
    280   Rsa = RsaNew ();
    281   if (Rsa == NULL) {
    282     DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: RsaNew() failed\n"));
    283     *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
    284     goto Done;
    285   }
    286 
    287   //
    288   // Set RSA Key Components.
    289   // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
    290   //
    291   CryptoStatus = RsaSetKey (Rsa, RsaKeyN, CertBlockRsa2048Sha256->PublicKey, sizeof(CertBlockRsa2048Sha256->PublicKey));
    292   if (!CryptoStatus) {
    293     DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: RsaSetKey(RsaKeyN) failed\n"));
    294     *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
    295     goto Done;
    296   }
    297   CryptoStatus = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));
    298   if (!CryptoStatus) {
    299     DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: RsaSetKey(RsaKeyE) failed\n"));
    300     *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
    301     goto Done;
    302   }
    303 
    304   //
    305   // Hash data payload with SHA256.
    306   //
    307   ZeroMem (Digest, SHA256_DIGEST_SIZE);
    308   CryptoStatus = Sha256Init (HashContext);
    309   if (!CryptoStatus) {
    310     DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Sha256Init() failed\n"));
    311     *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
    312     goto Done;
    313   }
    314   PERF_START (NULL, "RsaShaData", "PEI", 0);
    315   CryptoStatus = Sha256Update (HashContext, *OutputBuffer, OutputBufferSize);
    316   PERF_END (NULL, "RsaShaData", "PEI", 0);
    317   if (!CryptoStatus) {
    318     DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Sha256Update() failed\n"));
    319     *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
    320     goto Done;
    321   }
    322   CryptoStatus  = Sha256Final (HashContext, Digest);
    323   if (!CryptoStatus) {
    324     DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Sha256Final() failed\n"));
    325     *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
    326     goto Done;
    327   }
    328 
    329   //
    330   // Verify the RSA 2048 SHA 256 signature.
    331   //
    332   PERF_START (NULL, "RsaVerify", "PEI", 0);
    333   CryptoStatus = RsaPkcs1Verify (
    334                    Rsa,
    335                    Digest,
    336                    SHA256_DIGEST_SIZE,
    337                    CertBlockRsa2048Sha256->Signature,
    338                    sizeof (CertBlockRsa2048Sha256->Signature)
    339                    );
    340   PERF_END (NULL, "RsaVerify", "PEI", 0);
    341   if (!CryptoStatus) {
    342     //
    343     // If RSA 2048 SHA 256 signature verification fails, AUTH tested failed bit is set.
    344     //
    345     DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: RsaPkcs1Verify() failed\n"));
    346     *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
    347   }
    348 
    349 Done:
    350   //
    351   // Free allocated resources used to perform RSA 2048 SHA 256 signature verification
    352   //
    353   if (Rsa != NULL) {
    354     RsaFree (Rsa);
    355   }
    356   if (HashContext != NULL) {
    357     FreePool (HashContext);
    358   }
    359 
    360   DEBUG ((DEBUG_VERBOSE, "PeiRsa2048Sha256: Status = %r  AuthenticationStatus = %08x\n", Status, *AuthenticationStatus));
    361 
    362   return Status;
    363 }
    364 
    365 /**
    366   Register the handler to extract RSA 2048 SHA 256 guided section.
    367 
    368   @param  FileHandle   The handle of FFS header the loaded driver.
    369   @param  PeiServices  The pointer to the PEI services.
    370 
    371   @retval  EFI_SUCCESS           Register successfully.
    372   @retval  EFI_OUT_OF_RESOURCES  Not enough memory to register this handler.
    373 
    374 **/
    375 EFI_STATUS
    376 EFIAPI
    377 PeiRsa2048Sha256GuidedSectionExtractLibConstructor (
    378   IN EFI_PEI_FILE_HANDLE        FileHandle,
    379   IN CONST EFI_PEI_SERVICES     **PeiServices
    380   )
    381 {
    382   return ExtractGuidedSectionRegisterHandlers (
    383            &gEfiCertTypeRsa2048Sha256Guid,
    384            Rsa2048Sha256GuidedSectionGetInfo,
    385            Rsa2048Sha256GuidedSectionHandler
    386            );
    387 }
    388