From c04c4534c4a5093c116b0670c34d11df9440dd7b Mon Sep 17 00:00:00 2001 From: Pierre Gondois Date: Tue, 3 Sep 2024 18:04:39 +0200 Subject: MdePkg/DxeRngLib: Refactor Rng algorithm selection Add a library constructor which: - locate the RNG prototocol and keep a reference to it in order to avoid locating it multiple times (for each random number generation) - check which secure algorithm is available on the platform. This avoids to try each secure algorithm until finding one available for each random number generation call. Signed-off-by: Pierre Gondois --- MdePkg/Library/DxeRngLib/DxeRngLib.c | 187 +++++++++++++++++++++++++++------ MdePkg/Library/DxeRngLib/DxeRngLib.inf | 2 + 2 files changed, 158 insertions(+), 31 deletions(-) (limited to 'MdePkg') diff --git a/MdePkg/Library/DxeRngLib/DxeRngLib.c b/MdePkg/Library/DxeRngLib/DxeRngLib.c index 05c795759b..4b4efef0b4 100644 --- a/MdePkg/Library/DxeRngLib/DxeRngLib.c +++ b/MdePkg/Library/DxeRngLib/DxeRngLib.c @@ -1,17 +1,129 @@ /** @file Provides an implementation of the library class RngLib that uses the Rng protocol. - Copyright (c) 2023, Arm Limited. All rights reserved. + Copyright (c) 2023 - 2024, Arm Limited. All rights reserved. Copyright (c) Microsoft Corporation. All rights reserved. SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include +#include #include +#include #include #include +STATIC EFI_RNG_PROTOCOL *mRngProtocol; +STATIC UINTN mFirstAlgo = MAX_UINTN; + +typedef struct { + /// Guid of the secure algorithm. + EFI_GUID *Guid; + + /// Algorithm name. + CONST CHAR8 *Name; + + /// The algorithm is available for use. + BOOLEAN Available; +} SECURE_RNG_ALGO_ARRAY; + +// +// These represent UEFI SPEC defined algorithms that should be supported by +// the RNG protocol and are generally considered secure. +// +GLOBAL_REMOVE_IF_UNREFERENCED SECURE_RNG_ALGO_ARRAY mSecureHashAlgorithms[] = { + { + &gEfiRngAlgorithmSp80090Ctr256Guid, // SP800-90A DRBG CTR using AES-256 + "DRBG-CTR", + FALSE, + }, + { + &gEfiRngAlgorithmSp80090Hmac256Guid, // SP800-90A DRBG HMAC using SHA-256 + "DRBG-HMAC", + FALSE, + }, + { + &gEfiRngAlgorithmSp80090Hash256Guid, // SP800-90A DRBG Hash using SHA-256 + "DRBG-Hash", + FALSE, + }, + { + &gEfiRngAlgorithmRaw, // Raw data from NRBG (or TRNG) + "TRNG", + FALSE, + }, +}; + +/** + Constructor routine to probe the available secure Rng algorithms. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS Success. + @retval EFI_NOT_FOUND Not found. + @retval EFI_INVALID_PARAMETER Invalid parameter. +**/ +EFI_STATUS +EFIAPI +DxeRngLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + UINTN RngArraySize; + UINTN RngArrayCnt; + UINT32 Index; + UINT32 Index1; + EFI_RNG_ALGORITHM *RngArray; + + Status = gBS->LocateProtocol (&gEfiRngProtocolGuid, NULL, (VOID **)&mRngProtocol); + if (EFI_ERROR (Status) || (mRngProtocol == NULL)) { + DEBUG ((DEBUG_ERROR, "%a: Could not locate RNG protocol, Status = %r\n", __func__, Status)); + return Status; + } + + RngArraySize = 0; + + Status = mRngProtocol->GetInfo (mRngProtocol, &RngArraySize, NULL); + if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) { + return Status; + } else if (RngArraySize == 0) { + return EFI_NOT_FOUND; + } + + RngArrayCnt = RngArraySize / sizeof (*RngArray); + + RngArray = AllocateZeroPool (RngArraySize); + if (RngArray == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = mRngProtocol->GetInfo (mRngProtocol, &RngArraySize, RngArray); + if (EFI_ERROR (Status)) { + goto ExitHandler; + } + + for (Index = 0; Index < RngArrayCnt; Index++) { + for (Index1 = 0; Index1 < ARRAY_SIZE (mSecureHashAlgorithms); Index1++) { + if (CompareGuid (&RngArray[Index], mSecureHashAlgorithms[Index1].Guid)) { + mSecureHashAlgorithms[Index1].Available = TRUE; + if (mFirstAlgo == MAX_UINTN) { + mFirstAlgo = Index1; + } + + break; + } + } + } + +ExitHandler: + FreePool (RngArray); + return Status; +} + /** Routine Description: @@ -32,55 +144,68 @@ GenerateRandomNumberViaNist800Algorithm ( IN UINTN BufferSize ) { - EFI_STATUS Status; - EFI_RNG_PROTOCOL *RngProtocol; - - RngProtocol = NULL; + EFI_STATUS Status; + UINTN Index; + SECURE_RNG_ALGO_ARRAY *Algo; if (Buffer == NULL) { DEBUG ((DEBUG_ERROR, "%a: Buffer == NULL.\n", __func__)); return EFI_INVALID_PARAMETER; } - Status = gBS->LocateProtocol (&gEfiRngProtocolGuid, NULL, (VOID **)&RngProtocol); - if (EFI_ERROR (Status) || (RngProtocol == NULL)) { - DEBUG ((DEBUG_ERROR, "%a: Could not locate RNG prototocol, Status = %r\n", __func__, Status)); - return Status; - } - - Status = RngProtocol->GetRNG (RngProtocol, &gEfiRngAlgorithmSp80090Ctr256Guid, BufferSize, Buffer); - DEBUG ((DEBUG_INFO, "%a: GetRNG algorithm CTR-256 - Status = %r\n", __func__, Status)); - if (!EFI_ERROR (Status)) { - return Status; - } - - Status = RngProtocol->GetRNG (RngProtocol, &gEfiRngAlgorithmSp80090Hmac256Guid, BufferSize, Buffer); - DEBUG ((DEBUG_INFO, "%a: GetRNG algorithm HMAC-256 - Status = %r\n", __func__, Status)); - if (!EFI_ERROR (Status)) { - return Status; + if (mRngProtocol == NULL) { + return EFI_NOT_FOUND; } - Status = RngProtocol->GetRNG (RngProtocol, &gEfiRngAlgorithmSp80090Hash256Guid, BufferSize, Buffer); - DEBUG ((DEBUG_INFO, "%a: GetRNG algorithm Hash-256 - Status = %r\n", __func__, Status)); - if (!EFI_ERROR (Status)) { - return Status; + // Try the first available algorithm. + if (mFirstAlgo != MAX_UINTN) { + Algo = &mSecureHashAlgorithms[mFirstAlgo]; + Status = mRngProtocol->GetRNG (mRngProtocol, Algo->Guid, BufferSize, Buffer); + DEBUG (( + DEBUG_INFO, + "%a: GetRNG algorithm %a - Status = %r\n", + __func__, + Algo->Name, + Status + )); + if (!EFI_ERROR (Status)) { + return Status; + } + + Index = mFirstAlgo + 1; + } else { + Index = 0; } - Status = RngProtocol->GetRNG (RngProtocol, &gEfiRngAlgorithmRaw, BufferSize, Buffer); - DEBUG ((DEBUG_INFO, "%a: GetRNG algorithm Raw - Status = %r\n", __func__, Status)); - if (!EFI_ERROR (Status)) { - return Status; + // Iterate over other available algorithms. + for ( ; Index < ARRAY_SIZE (mSecureHashAlgorithms); Index++) { + Algo = &mSecureHashAlgorithms[Index]; + if (!Algo->Available) { + continue; + } + + Status = mRngProtocol->GetRNG (mRngProtocol, Algo->Guid, BufferSize, Buffer); + DEBUG (( + DEBUG_INFO, + "%a: GetRNG algorithm %a - Status = %r\n", + __func__, + Algo->Name, + Status + )); + if (!EFI_ERROR (Status)) { + return Status; + } } // If all the other methods have failed, use the default method from the RngProtocol - Status = RngProtocol->GetRNG (RngProtocol, NULL, BufferSize, Buffer); + Status = mRngProtocol->GetRNG (mRngProtocol, NULL, BufferSize, Buffer); DEBUG ((DEBUG_INFO, "%a: GetRNG algorithm default - Status = %r\n", __func__, Status)); if (!EFI_ERROR (Status)) { return Status; } // If we get to this point, we have failed - DEBUG ((DEBUG_ERROR, "%a: GetRNG() failed, staus = %r\n", __func__, Status)); + DEBUG ((DEBUG_ERROR, "%a: GetRNG() failed, Status = %r\n", __func__, Status)); return Status; }// GenerateRandomNumberViaNist800Algorithm() diff --git a/MdePkg/Library/DxeRngLib/DxeRngLib.inf b/MdePkg/Library/DxeRngLib/DxeRngLib.inf index 281fec4650..ca649585d4 100644 --- a/MdePkg/Library/DxeRngLib/DxeRngLib.inf +++ b/MdePkg/Library/DxeRngLib/DxeRngLib.inf @@ -15,6 +15,7 @@ MODULE_TYPE = DXE_DRIVER VERSION_STRING = 1.0 LIBRARY_CLASS = RngLib|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = DxeRngLibConstructor [Packages] MdePkg/MdePkg.dec @@ -24,6 +25,7 @@ [LibraryClasses] DebugLib + MemoryAllocationLib UefiBootServicesTableLib [Protocols] -- cgit v1.2.3