+/** @file\r
+\r
+ This library registers RSA 2048 SHA 256 guided section handler \r
+ to parse RSA 2048 SHA 256 encapsulation section and extract raw data.\r
+ It uses the BaseCrypyLib based on OpenSSL to authenticate the signature.\r
+\r
+Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution. The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php \r
+ \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+**/\r
+\r
+#include <PiDxe.h>\r
+#include <Protocol/Hash.h>\r
+#include <Protocol/SecurityPolicy.h>\r
+#include <Library/ExtractGuidedSectionLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Guid/WinCertificate.h>\r
+#include <Library/BaseCryptLib.h>\r
+#include <Library/PerformanceLib.h>\r
+#include <Guid/SecurityPkgTokenSpace.h>\r
+\r
+///\r
+/// RSA 2048 SHA 256 Guided Section header\r
+///\r
+typedef struct {\r
+ EFI_GUID_DEFINED_SECTION GuidedSectionHeader; ///< EFI guided section header\r
+ EFI_CERT_BLOCK_RSA_2048_SHA256 CertBlockRsa2048Sha256; ///< RSA 2048-bit Signature\r
+} RSA_2048_SHA_256_SECTION_HEADER;\r
+\r
+typedef struct {\r
+ EFI_GUID_DEFINED_SECTION2 GuidedSectionHeader; ///< EFI guided section header\r
+ EFI_CERT_BLOCK_RSA_2048_SHA256 CertBlockRsa2048Sha256; ///< RSA 2048-bit Signature\r
+} RSA_2048_SHA_256_SECTION2_HEADER;\r
+\r
+///\r
+/// Public Exponent of RSA Key.\r
+///\r
+CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };\r
+\r
+/**\r
+\r
+ GetInfo gets raw data size and attribute of the input guided section.\r
+ It first checks whether the input guid section is supported. \r
+ If not, EFI_INVALID_PARAMETER will return.\r
+\r
+ @param InputSection Buffer containing the input GUIDed section to be processed.\r
+ @param OutputBufferSize The size of OutputBuffer.\r
+ @param ScratchBufferSize The size of ScratchBuffer.\r
+ @param SectionAttribute The attribute of the input guided section.\r
+\r
+ @retval EFI_SUCCESS The size of destination buffer, the size of scratch buffer and \r
+ the attribute of the input section are successull retrieved.\r
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does not match this instance guid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Rsa2048Sha256GuidedSectionGetInfo (\r
+ IN CONST VOID *InputSection,\r
+ OUT UINT32 *OutputBufferSize,\r
+ OUT UINT32 *ScratchBufferSize,\r
+ OUT UINT16 *SectionAttribute\r
+ )\r
+{\r
+ if (IS_SECTION2 (InputSection)) {\r
+ //\r
+ // Check whether the input guid section is recognized.\r
+ //\r
+ if (!CompareGuid (\r
+ &gEfiCertTypeRsa2048Sha256Guid,\r
+ &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Retrieve the size and attribute of the input section data.\r
+ //\r
+ *SectionAttribute = ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->Attributes;\r
+ *ScratchBufferSize = 0;\r
+ *OutputBufferSize = SECTION2_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset;\r
+ } else {\r
+ //\r
+ // Check whether the input guid section is recognized.\r
+ //\r
+ if (!CompareGuid (\r
+ &gEfiCertTypeRsa2048Sha256Guid,\r
+ &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Retrieve the size and attribute of the input section data.\r
+ //\r
+ *SectionAttribute = ((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes;\r
+ *ScratchBufferSize = 0;\r
+ *OutputBufferSize = SECTION_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ Extraction handler tries to extract raw data from the input guided section.\r
+ It also does authentication check for RSA 2048 SHA 256 signature in the input guided section.\r
+ It first checks whether the input guid section is supported. \r
+ If not, EFI_INVALID_PARAMETER will return.\r
+\r
+ @param InputSection Buffer containing the input GUIDed section to be processed.\r
+ @param OutputBuffer Buffer to contain the output raw data allocated by the caller.\r
+ @param ScratchBuffer A pointer to a caller-allocated buffer for function internal use.\r
+ @param AuthenticationStatus A pointer to a caller-allocated UINT32 that indicates the\r
+ authentication status of the output buffer.\r
+\r
+ @retval EFI_SUCCESS Section Data and Auth Status is extracted successfully.\r
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does not match this instance guid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Rsa2048Sha256GuidedSectionHandler (\r
+ IN CONST VOID *InputSection,\r
+ OUT VOID **OutputBuffer,\r
+ IN VOID *ScratchBuffer, OPTIONAL\r
+ OUT UINT32 *AuthenticationStatus\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 OutputBufferSize;\r
+ VOID *DummyInterface;\r
+ EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlockRsa2048Sha256;\r
+ BOOLEAN CryptoStatus;\r
+ UINT8 Digest[SHA256_DIGEST_SIZE];\r
+ UINT8 *PublicKey;\r
+ UINTN PublicKeyBufferSize;\r
+ VOID *HashContext;\r
+ VOID *Rsa;\r
+ \r
+ HashContext = NULL;\r
+ Rsa = NULL;\r
+ \r
+ if (IS_SECTION2 (InputSection)) {\r
+ //\r
+ // Check whether the input guid section is recognized.\r
+ //\r
+ if (!CompareGuid (\r
+ &gEfiCertTypeRsa2048Sha256Guid,\r
+ &(((EFI_GUID_DEFINED_SECTION2 *)InputSection)->SectionDefinitionGuid))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ \r
+ //\r
+ // Get the RSA 2048 SHA 256 information.\r
+ //\r
+ CertBlockRsa2048Sha256 = &((RSA_2048_SHA_256_SECTION2_HEADER *) InputSection)->CertBlockRsa2048Sha256;\r
+ OutputBufferSize = SECTION2_SIZE (InputSection) - sizeof (RSA_2048_SHA_256_SECTION2_HEADER);\r
+ if ((((EFI_GUID_DEFINED_SECTION *)InputSection)->Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) {\r
+ PERF_START (NULL, "RsaCopy", "DXE", 0);\r
+ CopyMem (*OutputBuffer, (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION2_HEADER), OutputBufferSize);\r
+ PERF_END (NULL, "RsaCopy", "DXE", 0);\r
+ } else {\r
+ *OutputBuffer = (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION2_HEADER);\r
+ }\r
+\r
+ //\r
+ // Implicitly RSA 2048 SHA 256 GUIDed section should have STATUS_VALID bit set\r
+ //\r
+ ASSERT ((((EFI_GUID_DEFINED_SECTION2 *)InputSection)->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0);\r
+ *AuthenticationStatus = EFI_AUTH_STATUS_IMAGE_SIGNED;\r
+ } else {\r
+ //\r
+ // Check whether the input guid section is recognized.\r
+ //\r
+ if (!CompareGuid (\r
+ &gEfiCertTypeRsa2048Sha256Guid,\r
+ &(((EFI_GUID_DEFINED_SECTION *)InputSection)->SectionDefinitionGuid))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ \r
+ //\r
+ // Get the RSA 2048 SHA 256 information.\r
+ //\r
+ CertBlockRsa2048Sha256 = &((RSA_2048_SHA_256_SECTION_HEADER *)InputSection)->CertBlockRsa2048Sha256;\r
+ OutputBufferSize = SECTION_SIZE (InputSection) - sizeof (RSA_2048_SHA_256_SECTION_HEADER);\r
+ if ((((EFI_GUID_DEFINED_SECTION *)InputSection)->Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) {\r
+ PERF_START (NULL, "RsaCopy", "DXE", 0);\r
+ CopyMem (*OutputBuffer, (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION_HEADER), OutputBufferSize);\r
+ PERF_END (NULL, "RsaCopy", "DXE", 0);\r
+ } else {\r
+ *OutputBuffer = (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION_HEADER);\r
+ }\r
+\r
+ //\r
+ // Implicitly RSA 2048 SHA 256 GUIDed section should have STATUS_VALID bit set\r
+ //\r
+ ASSERT ((((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0);\r
+ *AuthenticationStatus = EFI_AUTH_STATUS_IMAGE_SIGNED;\r
+ }\r
+\r
+ //\r
+ // Check whether there exists EFI_SECURITY_POLICY_PROTOCOL_GUID.\r
+ //\r
+ Status = gBS->LocateProtocol (&gEfiSecurityPolicyProtocolGuid, NULL, &DummyInterface);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // If SecurityPolicy Protocol exist, AUTH platform override bit is set.\r
+ //\r
+ *AuthenticationStatus |= EFI_AUTH_STATUS_PLATFORM_OVERRIDE;\r
+ \r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // All paths from here return EFI_SUCESS and result is returned in AuthenticationStatus\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ \r
+ //\r
+ // Fail if the HashType is not SHA 256\r
+ //\r
+ if (!CompareGuid (&gEfiHashAlgorithmSha256Guid, &CertBlockRsa2048Sha256->HashType)) {\r
+ DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: HASH type of section is not supported\n"));\r
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Allocate hash context buffer required for SHA 256\r
+ //\r
+ HashContext = AllocatePool (Sha256GetContextSize ());\r
+ if (HashContext == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: Can not allocate hash context\n"));\r
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Hash public key from data payload with SHA256.\r
+ //\r
+ ZeroMem (Digest, SHA256_DIGEST_SIZE);\r
+ CryptoStatus = Sha256Init (HashContext);\r
+ if (!CryptoStatus) {\r
+ DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: Sha256Init() failed\n"));\r
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;\r
+ goto Done;\r
+ }\r
+ CryptoStatus = Sha256Update (HashContext, &CertBlockRsa2048Sha256->PublicKey, sizeof(CertBlockRsa2048Sha256->PublicKey));\r
+ if (!CryptoStatus) {\r
+ DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: Sha256Update() failed\n"));\r
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;\r
+ goto Done;\r
+ }\r
+ CryptoStatus = Sha256Final (HashContext, Digest);\r
+ if (!CryptoStatus) {\r
+ DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: Sha256Final() failed\n"));\r
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;\r
+ goto Done;\r
+ }\r
+ \r
+ //\r
+ // Fail if the PublicKey is not one of the public keys in PcdRsa2048Sha256PublicKeyBuffer\r
+ //\r
+ PublicKey = (UINT8 *)PcdGetPtr (PcdRsa2048Sha256PublicKeyBuffer);\r
+ DEBUG ((DEBUG_VERBOSE, "DxePcdRsa2048Sha256: PublicKeyBuffer = %p\n", PublicKey));\r
+ ASSERT (PublicKey != NULL);\r
+ DEBUG ((DEBUG_VERBOSE, "DxePcdRsa2048Sha256: PublicKeyBuffer Token = %08x\n", PcdToken (PcdRsa2048Sha256PublicKeyBuffer)));\r
+ PublicKeyBufferSize = LibPcdGetExSize (&gEfiSecurityPkgTokenSpaceGuid, PcdToken (PcdRsa2048Sha256PublicKeyBuffer));\r
+ DEBUG ((DEBUG_VERBOSE, "DxePcdRsa2048Sha256: PublicKeyBuffer Size = %08x\n", PublicKeyBufferSize));\r
+ ASSERT ((PublicKeyBufferSize % SHA256_DIGEST_SIZE) == 0);\r
+ CryptoStatus = FALSE;\r
+ while (PublicKeyBufferSize != 0) {\r
+ if (CompareMem (Digest, PublicKey, SHA256_DIGEST_SIZE) == 0) {\r
+ CryptoStatus = TRUE;\r
+ break;\r
+ }\r
+ PublicKey = PublicKey + SHA256_DIGEST_SIZE;\r
+ PublicKeyBufferSize = PublicKeyBufferSize - SHA256_DIGEST_SIZE;\r
+ }\r
+ if (!CryptoStatus) {\r
+ DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: Public key in section is not supported\n"));\r
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Generate & Initialize RSA Context.\r
+ //\r
+ Rsa = RsaNew ();\r
+ if (Rsa == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: RsaNew() failed\n"));\r
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;\r
+ goto Done;\r
+ }\r
+ \r
+ // \r
+ // Set RSA Key Components.\r
+ // NOTE: Only N and E are needed to be set as RSA public key for signature verification.\r
+ //\r
+ CryptoStatus = RsaSetKey (Rsa, RsaKeyN, CertBlockRsa2048Sha256->PublicKey, sizeof(CertBlockRsa2048Sha256->PublicKey));\r
+ if (!CryptoStatus) {\r
+ DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: RsaSetKey(RsaKeyN) failed\n"));\r
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;\r
+ goto Done;\r
+ }\r
+ CryptoStatus = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));\r
+ if (!CryptoStatus) {\r
+ DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: RsaSetKey(RsaKeyE) failed\n"));\r
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Hash data payload with SHA256.\r
+ //\r
+ ZeroMem (Digest, SHA256_DIGEST_SIZE);\r
+ CryptoStatus = Sha256Init (HashContext);\r
+ if (!CryptoStatus) {\r
+ DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: Sha256Init() failed\n"));\r
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;\r
+ goto Done;\r
+ }\r
+ PERF_START (NULL, "RsaShaData", "DXE", 0);\r
+ CryptoStatus = Sha256Update (HashContext, *OutputBuffer, OutputBufferSize);\r
+ PERF_END (NULL, "RsaShaData", "DXE", 0);\r
+ if (!CryptoStatus) {\r
+ DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: Sha256Update() failed\n"));\r
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;\r
+ goto Done;\r
+ }\r
+ CryptoStatus = Sha256Final (HashContext, Digest);\r
+ if (!CryptoStatus) {\r
+ DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: Sha256Final() failed\n"));\r
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Verify the RSA 2048 SHA 256 signature.\r
+ //\r
+ PERF_START (NULL, "RsaVerify", "DXE", 0);\r
+ CryptoStatus = RsaPkcs1Verify (\r
+ Rsa, \r
+ Digest, \r
+ SHA256_DIGEST_SIZE, \r
+ CertBlockRsa2048Sha256->Signature, \r
+ sizeof (CertBlockRsa2048Sha256->Signature)\r
+ );\r
+ PERF_END (NULL, "RsaVerify", "DXE", 0);\r
+ if (!CryptoStatus) {\r
+ //\r
+ // If RSA 2048 SHA 256 signature verification fails, AUTH tested failed bit is set.\r
+ //\r
+ DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: RsaPkcs1Verify() failed\n"));\r
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;\r
+ }\r
+\r
+Done:\r
+ //\r
+ // Free allocated resources used to perform RSA 2048 SHA 256 signature verification\r
+ //\r
+ if (Rsa != NULL) {\r
+ RsaFree (Rsa);\r
+ }\r
+ if (HashContext != NULL) {\r
+ FreePool (HashContext);\r
+ }\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "DxeRsa2048Sha256: Status = %r AuthenticationStatus = %08x\n", Status, *AuthenticationStatus));\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Register the handler to extract RSA 2048 SHA 256 guided section.\r
+\r
+ @param ImageHandle ImageHandle of the loaded driver.\r
+ @param SystemTable Pointer to the EFI System Table.\r
+\r
+ @retval EFI_SUCCESS Register successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to register this handler.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DxeRsa2048Sha256GuidedSectionExtractLibConstructor (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ return ExtractGuidedSectionRegisterHandlers (\r
+ &gEfiCertTypeRsa2048Sha256Guid,\r
+ Rsa2048Sha256GuidedSectionGetInfo,\r
+ Rsa2048Sha256GuidedSectionHandler\r
+ );\r
+}\r