Home | History | Annotate | Download | only in FmpAuthenticationLibRsa2048Sha256
      1 /** @file
      2   FMP Authentication RSA2048SHA256 handler.
      3   Provide generic FMP authentication functions for DXE/PEI post memory phase.
      4 
      5   Caution: This module requires additional review when modified.
      6   This module will have external input - capsule image.
      7   This external input must be validated carefully to avoid security issue like
      8   buffer overflow, integer overflow.
      9 
     10   FmpAuthenticatedHandlerRsa2048Sha256(), AuthenticateFmpImage() will receive
     11   untrusted input and do basic validation.
     12 
     13   Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
     14   This program and the accompanying materials
     15   are licensed and made available under the terms and conditions of the BSD License
     16   which accompanies this distribution.  The full text of the license may be found at
     17   http://opensource.org/licenses/bsd-license.php
     18 
     19   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     20   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     21 
     22 **/
     23 
     24 #include <Uefi.h>
     25 
     26 #include <Guid/SystemResourceTable.h>
     27 #include <Guid/FirmwareContentsSigned.h>
     28 #include <Guid/WinCertificate.h>
     29 
     30 #include <Library/BaseLib.h>
     31 #include <Library/BaseMemoryLib.h>
     32 #include <Library/DebugLib.h>
     33 #include <Library/MemoryAllocationLib.h>
     34 #include <Library/BaseCryptLib.h>
     35 #include <Library/FmpAuthenticationLib.h>
     36 #include <Library/PcdLib.h>
     37 #include <Protocol/FirmwareManagement.h>
     38 #include <Guid/SystemResourceTable.h>
     39 
     40 ///
     41 /// Public Exponent of RSA Key.
     42 ///
     43 STATIC CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };
     44 
     45 /**
     46   The handler is used to do the authentication for FMP capsule based upon
     47   EFI_FIRMWARE_IMAGE_AUTHENTICATION.
     48 
     49   Caution: This function may receive untrusted input.
     50 
     51   This function assumes the caller AuthenticateFmpImage()
     52   already did basic validation for EFI_FIRMWARE_IMAGE_AUTHENTICATION.
     53 
     54   @param[in]  Image                   Points to an FMP authentication image, started from EFI_FIRMWARE_IMAGE_AUTHENTICATION.
     55   @param[in]  ImageSize               Size of the authentication image in bytes.
     56   @param[in]  PublicKeyData           The public key data used to validate the signature.
     57   @param[in]  PublicKeyDataLength     The length of the public key data.
     58 
     59   @retval RETURN_SUCCESS            Authentication pass.
     60                                     The LastAttemptStatus should be LAST_ATTEMPT_STATUS_SUCCESS.
     61   @retval RETURN_SECURITY_VIOLATION Authentication fail.
     62                                     The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR.
     63   @retval RETURN_INVALID_PARAMETER  The image is in an invalid format.
     64                                     The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT.
     65   @retval RETURN_OUT_OF_RESOURCES   No Authentication handler associated with CertType.
     66                                     The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES.
     67 **/
     68 RETURN_STATUS
     69 FmpAuthenticatedHandlerRsa2048Sha256 (
     70   IN EFI_FIRMWARE_IMAGE_AUTHENTICATION  *Image,
     71   IN UINTN                              ImageSize,
     72   IN CONST UINT8                        *PublicKeyData,
     73   IN UINTN                              PublicKeyDataLength
     74   )
     75 {
     76   RETURN_STATUS                             Status;
     77   EFI_CERT_BLOCK_RSA_2048_SHA256            *CertBlockRsa2048Sha256;
     78   BOOLEAN                                   CryptoStatus;
     79   UINT8                                     Digest[SHA256_DIGEST_SIZE];
     80   UINT8                                     *PublicKey;
     81   UINTN                                     PublicKeyBufferSize;
     82   VOID                                      *HashContext;
     83   VOID                                      *Rsa;
     84 
     85   DEBUG ((DEBUG_INFO, "FmpAuthenticatedHandlerRsa2048Sha256 - Image: 0x%08x - 0x%08x\n", (UINTN)Image, (UINTN)ImageSize));
     86 
     87   if (Image->AuthInfo.Hdr.dwLength != OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData) + sizeof(EFI_CERT_BLOCK_RSA_2048_SHA256)) {
     88     DEBUG((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256 - dwLength: 0x%04x, dwLength - 0x%04x\n", (UINTN)Image->AuthInfo.Hdr.dwLength, (UINTN)OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData) + sizeof(EFI_CERT_BLOCK_RSA_2048_SHA256)));
     89     return RETURN_INVALID_PARAMETER;
     90   }
     91 
     92   CertBlockRsa2048Sha256 = (EFI_CERT_BLOCK_RSA_2048_SHA256 *)Image->AuthInfo.CertData;
     93   if (!CompareGuid(&CertBlockRsa2048Sha256->HashType, &gEfiHashAlgorithmSha256Guid)) {
     94     DEBUG((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256 - HashType: %g, expect - %g\n", &CertBlockRsa2048Sha256->HashType, &gEfiHashAlgorithmSha256Guid));
     95     return RETURN_INVALID_PARAMETER;
     96   }
     97 
     98   HashContext = NULL;
     99   Rsa = NULL;
    100 
    101   //
    102   // Allocate hash context buffer required for SHA 256
    103   //
    104   HashContext = AllocatePool (Sha256GetContextSize ());
    105   if (HashContext == NULL) {
    106     CryptoStatus = FALSE;
    107     DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Can not allocate hash context\n"));
    108     Status = RETURN_OUT_OF_RESOURCES;
    109     goto Done;
    110   }
    111 
    112   //
    113   // Hash public key from data payload with SHA256.
    114   //
    115   ZeroMem (Digest, SHA256_DIGEST_SIZE);
    116   CryptoStatus = Sha256Init (HashContext);
    117   if (!CryptoStatus) {
    118     DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Sha256Init() failed\n"));
    119     Status = RETURN_OUT_OF_RESOURCES;
    120     goto Done;
    121   }
    122   CryptoStatus = Sha256Update (HashContext, &CertBlockRsa2048Sha256->PublicKey, sizeof(CertBlockRsa2048Sha256->PublicKey));
    123   if (!CryptoStatus) {
    124     DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Sha256Update() failed\n"));
    125     Status = RETURN_OUT_OF_RESOURCES;
    126     goto Done;
    127   }
    128   CryptoStatus  = Sha256Final (HashContext, Digest);
    129   if (!CryptoStatus) {
    130     DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Sha256Final() failed\n"));
    131     Status = RETURN_OUT_OF_RESOURCES;
    132     goto Done;
    133   }
    134 
    135   //
    136   // Fail if the PublicKey is not one of the public keys in PcdRsa2048Sha256PublicKeyBuffer
    137   //
    138   PublicKey = (VOID *)PublicKeyData;
    139   PublicKeyBufferSize = PublicKeyDataLength;
    140   CryptoStatus = FALSE;
    141   while (PublicKeyBufferSize != 0) {
    142     if (CompareMem (Digest, PublicKey, SHA256_DIGEST_SIZE) == 0) {
    143       CryptoStatus = TRUE;
    144       break;
    145     }
    146     PublicKey = PublicKey + SHA256_DIGEST_SIZE;
    147     PublicKeyBufferSize = PublicKeyBufferSize - SHA256_DIGEST_SIZE;
    148   }
    149   if (!CryptoStatus) {
    150     DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Public key in section is not supported\n"));
    151     Status = RETURN_SECURITY_VIOLATION;
    152     goto Done;
    153   }
    154 
    155   //
    156   // Generate & Initialize RSA Context.
    157   //
    158   Rsa = RsaNew ();
    159   if (Rsa == NULL) {
    160     CryptoStatus = FALSE;
    161     DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: RsaNew() failed\n"));
    162     Status = RETURN_OUT_OF_RESOURCES;
    163     goto Done;
    164   }
    165 
    166   //
    167   // Set RSA Key Components.
    168   // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
    169   //
    170   CryptoStatus = RsaSetKey (Rsa, RsaKeyN, CertBlockRsa2048Sha256->PublicKey, sizeof(CertBlockRsa2048Sha256->PublicKey));
    171   if (!CryptoStatus) {
    172     DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: RsaSetKey(RsaKeyN) failed\n"));
    173     Status = RETURN_OUT_OF_RESOURCES;
    174     goto Done;
    175   }
    176   CryptoStatus = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));
    177   if (!CryptoStatus) {
    178     DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: RsaSetKey(RsaKeyE) failed\n"));
    179     Status = RETURN_OUT_OF_RESOURCES;
    180     goto Done;
    181   }
    182 
    183   //
    184   // Hash data payload with SHA256.
    185   //
    186   ZeroMem (Digest, SHA256_DIGEST_SIZE);
    187   CryptoStatus = Sha256Init (HashContext);
    188   if (!CryptoStatus) {
    189     DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Sha256Init() failed\n"));
    190     Status = RETURN_OUT_OF_RESOURCES;
    191     goto Done;
    192   }
    193 
    194   // It is a signature across the variable data and the Monotonic Count value.
    195   CryptoStatus = Sha256Update (
    196                    HashContext,
    197                    (UINT8 *)Image + sizeof(Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength,
    198                    ImageSize - sizeof(Image->MonotonicCount) - Image->AuthInfo.Hdr.dwLength
    199                    );
    200   if (!CryptoStatus) {
    201     DEBUG((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Sha256Update() failed\n"));
    202     Status = RETURN_OUT_OF_RESOURCES;
    203     goto Done;
    204   }
    205   CryptoStatus = Sha256Update (
    206                    HashContext,
    207                    (UINT8 *)&Image->MonotonicCount,
    208                    sizeof(Image->MonotonicCount)
    209                    );
    210   if (!CryptoStatus) {
    211     DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Sha256Update() failed\n"));
    212     Status = RETURN_OUT_OF_RESOURCES;
    213     goto Done;
    214   }
    215   CryptoStatus  = Sha256Final (HashContext, Digest);
    216   if (!CryptoStatus) {
    217     DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Sha256Final() failed\n"));
    218     Status = RETURN_OUT_OF_RESOURCES;
    219     goto Done;
    220   }
    221 
    222   //
    223   // Verify the RSA 2048 SHA 256 signature.
    224   //
    225   CryptoStatus = RsaPkcs1Verify (
    226                    Rsa,
    227                    Digest,
    228                    SHA256_DIGEST_SIZE,
    229                    CertBlockRsa2048Sha256->Signature,
    230                    sizeof (CertBlockRsa2048Sha256->Signature)
    231                    );
    232   if (!CryptoStatus) {
    233     //
    234     // If RSA 2048 SHA 256 signature verification fails, AUTH tested failed bit is set.
    235     //
    236     DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: RsaPkcs1Verify() failed\n"));
    237     Status = RETURN_SECURITY_VIOLATION;
    238     goto Done;
    239   }
    240   DEBUG ((DEBUG_INFO, "FmpAuthenticatedHandlerRsa2048Sha256: PASS verification\n"));
    241 
    242   Status = RETURN_SUCCESS;
    243 
    244 Done:
    245   //
    246   // Free allocated resources used to perform RSA 2048 SHA 256 signature verification
    247   //
    248   if (Rsa != NULL) {
    249     RsaFree (Rsa);
    250   }
    251   if (HashContext != NULL) {
    252     FreePool (HashContext);
    253   }
    254 
    255   return Status;
    256 }
    257 
    258 /**
    259   The function is used to do the authentication for FMP capsule based upon
    260   EFI_FIRMWARE_IMAGE_AUTHENTICATION.
    261 
    262   The FMP capsule image should start with EFI_FIRMWARE_IMAGE_AUTHENTICATION,
    263   followed by the payload.
    264 
    265   If the return status is RETURN_SUCCESS, the caller may continue the rest
    266   FMP update process.
    267   If the return status is NOT RETURN_SUCCESS, the caller should stop the FMP
    268   update process and convert the return status to LastAttemptStatus
    269   to indicate that FMP update fails.
    270   The LastAttemptStatus can be got from ESRT table or via
    271   EFI_FIRMWARE_MANAGEMENT_PROTOCOL.GetImageInfo().
    272 
    273   Caution: This function may receive untrusted input.
    274 
    275   @param[in]  Image                   Points to an FMP authentication image, started from EFI_FIRMWARE_IMAGE_AUTHENTICATION.
    276   @param[in]  ImageSize               Size of the authentication image in bytes.
    277   @param[in]  PublicKeyData           The public key data used to validate the signature.
    278   @param[in]  PublicKeyDataLength     The length of the public key data.
    279 
    280   @retval RETURN_SUCCESS            Authentication pass.
    281                                     The LastAttemptStatus should be LAST_ATTEMPT_STATUS_SUCCESS.
    282   @retval RETURN_SECURITY_VIOLATION Authentication fail.
    283                                     The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR.
    284   @retval RETURN_INVALID_PARAMETER  The image is in an invalid format.
    285                                     The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT.
    286   @retval RETURN_UNSUPPORTED        No Authentication handler associated with CertType.
    287                                     The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT.
    288   @retval RETURN_UNSUPPORTED        Image or ImageSize is invalid.
    289                                     The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT.
    290   @retval RETURN_OUT_OF_RESOURCES   No Authentication handler associated with CertType.
    291                                     The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES.
    292 **/
    293 RETURN_STATUS
    294 EFIAPI
    295 AuthenticateFmpImage (
    296   IN EFI_FIRMWARE_IMAGE_AUTHENTICATION  *Image,
    297   IN UINTN                              ImageSize,
    298   IN CONST UINT8                        *PublicKeyData,
    299   IN UINTN                              PublicKeyDataLength
    300   )
    301 {
    302   GUID                                      *CertType;
    303   EFI_STATUS                                Status;
    304 
    305   if ((Image == NULL) || (ImageSize == 0)) {
    306     return RETURN_UNSUPPORTED;
    307   }
    308 
    309   if ((PublicKeyDataLength % SHA256_DIGEST_SIZE) != 0) {
    310     DEBUG ((DEBUG_ERROR, "PublicKeyDataLength is not multiple SHA256 size\n"));
    311     return RETURN_UNSUPPORTED;
    312   }
    313 
    314   if (ImageSize < sizeof(EFI_FIRMWARE_IMAGE_AUTHENTICATION)) {
    315     DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - ImageSize too small\n"));
    316     return RETURN_INVALID_PARAMETER;
    317   }
    318   if (Image->AuthInfo.Hdr.dwLength <= OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData)) {
    319     DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - dwLength too small\n"));
    320     return RETURN_INVALID_PARAMETER;
    321   }
    322   if (Image->AuthInfo.Hdr.dwLength > MAX_UINTN - sizeof(UINT64)) {
    323     DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - dwLength too big\n"));
    324     return RETURN_INVALID_PARAMETER;
    325   }
    326   if (ImageSize <= sizeof(Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength) {
    327     DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - ImageSize too small\n"));
    328     return RETURN_INVALID_PARAMETER;
    329   }
    330   if (Image->AuthInfo.Hdr.wRevision != 0x0200) {
    331     DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - wRevision: 0x%02x, expect - 0x%02x\n", (UINTN)Image->AuthInfo.Hdr.wRevision, (UINTN)0x0200));
    332     return RETURN_INVALID_PARAMETER;
    333   }
    334   if (Image->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) {
    335     DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - wCertificateType: 0x%02x, expect - 0x%02x\n", (UINTN)Image->AuthInfo.Hdr.wCertificateType, (UINTN)WIN_CERT_TYPE_EFI_GUID));
    336     return RETURN_INVALID_PARAMETER;
    337   }
    338 
    339   CertType = &Image->AuthInfo.CertType;
    340   DEBUG((DEBUG_INFO, "AuthenticateFmpImage - CertType: %g\n", CertType));
    341 
    342   if (CompareGuid (&gEfiCertTypeRsa2048Sha256Guid, CertType)) {
    343     //
    344     // Call the match handler to extract raw data for the input section data.
    345     //
    346     Status = FmpAuthenticatedHandlerRsa2048Sha256 (
    347                Image,
    348                ImageSize,
    349                PublicKeyData,
    350                PublicKeyDataLength
    351                );
    352     return Status;
    353   }
    354 
    355   //
    356   // Not found, the input guided section is not supported.
    357   //
    358   return RETURN_UNSUPPORTED;
    359 }
    360 
    361