/** @file\r
Provides an implementation of the library class RngLib that uses the Rng protocol.\r
\r
- Copyright (c) 2023, Arm Limited. All rights reserved.\r
+ Copyright (c) 2023 - 2024, Arm Limited. All rights reserved.\r
Copyright (c) Microsoft Corporation. All rights reserved.\r
SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
#include <Uefi.h>\r
#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
#include <Library/DebugLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
#include <Library/RngLib.h>\r
#include <Protocol/Rng.h>\r
\r
+STATIC EFI_RNG_PROTOCOL *mRngProtocol;\r
+STATIC UINTN mFirstAlgo = MAX_UINTN;\r
+\r
+typedef struct {\r
+ /// Guid of the secure algorithm.\r
+ EFI_GUID *Guid;\r
+\r
+ /// Algorithm name.\r
+ CONST CHAR8 *Name;\r
+\r
+ /// The algorithm is available for use.\r
+ BOOLEAN Available;\r
+} SECURE_RNG_ALGO_ARRAY;\r
+\r
+//\r
+// These represent UEFI SPEC defined algorithms that should be supported by\r
+// the RNG protocol and are generally considered secure.\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED SECURE_RNG_ALGO_ARRAY mSecureHashAlgorithms[] = {\r
+ {\r
+ &gEfiRngAlgorithmSp80090Ctr256Guid, // SP800-90A DRBG CTR using AES-256\r
+ "DRBG-CTR",\r
+ FALSE,\r
+ },\r
+ {\r
+ &gEfiRngAlgorithmSp80090Hmac256Guid, // SP800-90A DRBG HMAC using SHA-256\r
+ "DRBG-HMAC",\r
+ FALSE,\r
+ },\r
+ {\r
+ &gEfiRngAlgorithmSp80090Hash256Guid, // SP800-90A DRBG Hash using SHA-256\r
+ "DRBG-Hash",\r
+ FALSE,\r
+ },\r
+ {\r
+ &gEfiRngAlgorithmRaw, // Raw data from NRBG (or TRNG)\r
+ "TRNG",\r
+ FALSE,\r
+ },\r
+};\r
+\r
+/**\r
+ Constructor routine to probe the available secure Rng algorithms.\r
+\r
+ @param ImageHandle The firmware allocated handle for the EFI image.\r
+ @param SystemTable A pointer to the EFI System Table.\r
+\r
+ @retval EFI_SUCCESS Success.\r
+ @retval EFI_NOT_FOUND Not found.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DxeRngLibConstructor (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN RngArraySize;\r
+ UINTN RngArrayCnt;\r
+ UINT32 Index;\r
+ UINT32 Index1;\r
+ EFI_RNG_ALGORITHM *RngArray;\r
+\r
+ Status = gBS->LocateProtocol (&gEfiRngProtocolGuid, NULL, (VOID **)&mRngProtocol);\r
+ if (EFI_ERROR (Status) || (mRngProtocol == NULL)) {\r
+ DEBUG ((DEBUG_ERROR, "%a: Could not locate RNG protocol, Status = %r\n", __func__, Status));\r
+ return Status;\r
+ }\r
+\r
+ RngArraySize = 0;\r
+\r
+ Status = mRngProtocol->GetInfo (mRngProtocol, &RngArraySize, NULL);\r
+ if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {\r
+ return Status;\r
+ } else if (RngArraySize == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ RngArrayCnt = RngArraySize / sizeof (*RngArray);\r
+\r
+ RngArray = AllocateZeroPool (RngArraySize);\r
+ if (RngArray == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = mRngProtocol->GetInfo (mRngProtocol, &RngArraySize, RngArray);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ExitHandler;\r
+ }\r
+\r
+ for (Index = 0; Index < RngArrayCnt; Index++) {\r
+ for (Index1 = 0; Index1 < ARRAY_SIZE (mSecureHashAlgorithms); Index1++) {\r
+ if (CompareGuid (&RngArray[Index], mSecureHashAlgorithms[Index1].Guid)) {\r
+ mSecureHashAlgorithms[Index1].Available = TRUE;\r
+ if (mFirstAlgo == MAX_UINTN) {\r
+ mFirstAlgo = Index1;\r
+ }\r
+\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ExitHandler:\r
+ FreePool (RngArray);\r
+ return Status;\r
+}\r
+\r
/**\r
Routine Description:\r
\r
IN UINTN BufferSize\r
)\r
{\r
- EFI_STATUS Status;\r
- EFI_RNG_PROTOCOL *RngProtocol;\r
-\r
- RngProtocol = NULL;\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ SECURE_RNG_ALGO_ARRAY *Algo;\r
\r
if (Buffer == NULL) {\r
DEBUG ((DEBUG_ERROR, "%a: Buffer == NULL.\n", __func__));\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- Status = gBS->LocateProtocol (&gEfiRngProtocolGuid, NULL, (VOID **)&RngProtocol);\r
- if (EFI_ERROR (Status) || (RngProtocol == NULL)) {\r
- DEBUG ((DEBUG_ERROR, "%a: Could not locate RNG prototocol, Status = %r\n", __func__, Status));\r
- return Status;\r
- }\r
-\r
- Status = RngProtocol->GetRNG (RngProtocol, &gEfiRngAlgorithmSp80090Ctr256Guid, BufferSize, Buffer);\r
- DEBUG ((DEBUG_INFO, "%a: GetRNG algorithm CTR-256 - Status = %r\n", __func__, Status));\r
- if (!EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- Status = RngProtocol->GetRNG (RngProtocol, &gEfiRngAlgorithmSp80090Hmac256Guid, BufferSize, Buffer);\r
- DEBUG ((DEBUG_INFO, "%a: GetRNG algorithm HMAC-256 - Status = %r\n", __func__, Status));\r
- if (!EFI_ERROR (Status)) {\r
- return Status;\r
+ if (mRngProtocol == NULL) {\r
+ return EFI_NOT_FOUND;\r
}\r
\r
- Status = RngProtocol->GetRNG (RngProtocol, &gEfiRngAlgorithmSp80090Hash256Guid, BufferSize, Buffer);\r
- DEBUG ((DEBUG_INFO, "%a: GetRNG algorithm Hash-256 - Status = %r\n", __func__, Status));\r
- if (!EFI_ERROR (Status)) {\r
- return Status;\r
+ // Try the first available algorithm.\r
+ if (mFirstAlgo != MAX_UINTN) {\r
+ Algo = &mSecureHashAlgorithms[mFirstAlgo];\r
+ Status = mRngProtocol->GetRNG (mRngProtocol, Algo->Guid, BufferSize, Buffer);\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "%a: GetRNG algorithm %a - Status = %r\n",\r
+ __func__,\r
+ Algo->Name,\r
+ Status\r
+ ));\r
+ if (!EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Index = mFirstAlgo + 1;\r
+ } else {\r
+ Index = 0;\r
}\r
\r
- Status = RngProtocol->GetRNG (RngProtocol, &gEfiRngAlgorithmRaw, BufferSize, Buffer);\r
- DEBUG ((DEBUG_INFO, "%a: GetRNG algorithm Raw - Status = %r\n", __func__, Status));\r
- if (!EFI_ERROR (Status)) {\r
- return Status;\r
+ // Iterate over other available algorithms.\r
+ for ( ; Index < ARRAY_SIZE (mSecureHashAlgorithms); Index++) {\r
+ Algo = &mSecureHashAlgorithms[Index];\r
+ if (!Algo->Available) {\r
+ continue;\r
+ }\r
+\r
+ Status = mRngProtocol->GetRNG (mRngProtocol, Algo->Guid, BufferSize, Buffer);\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "%a: GetRNG algorithm %a - Status = %r\n",\r
+ __func__,\r
+ Algo->Name,\r
+ Status\r
+ ));\r
+ if (!EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
}\r
\r
// If all the other methods have failed, use the default method from the RngProtocol\r
- Status = RngProtocol->GetRNG (RngProtocol, NULL, BufferSize, Buffer);\r
+ Status = mRngProtocol->GetRNG (mRngProtocol, NULL, BufferSize, Buffer);\r
DEBUG ((DEBUG_INFO, "%a: GetRNG algorithm default - Status = %r\n", __func__, Status));\r
if (!EFI_ERROR (Status)) {\r
return Status;\r
}\r
\r
// If we get to this point, we have failed\r
- DEBUG ((DEBUG_ERROR, "%a: GetRNG() failed, staus = %r\n", __func__, Status));\r
+ DEBUG ((DEBUG_ERROR, "%a: GetRNG() failed, Status = %r\n", __func__, Status));\r
\r
return Status;\r
}// GenerateRandomNumberViaNist800Algorithm()\r