From edf1450f3e3958bf5585f7847453d1eae635d0aa Mon Sep 17 00:00:00 2001 From: Michael Kubacki Date: Tue, 4 Jun 2024 23:09:33 -0400 Subject: SecurityPkg: Add RngPei REF:https://github.com/tianocore/edk2/issues/10529 The `RngPei` PEIM can be used if RNG should be provided over a dynamic binary interface to other PEIMs on a platform. Tested with: - SecurityPkg CI - Verify RNG linked with RngLib is executed as expected - Verify random numbers are generated successfully with a valid RngLib Integration instructions: Use the `RngPei` module if a platform needs to produce `gEfiRngPpiGuid`. The platform should usually link a different `RngLib` instance to `RngPei` than other PEIMs that may use the RNG PPI produced since `RngPei` is responsible for producing the PPI. For example, a `RngLib` instance that uses the rdrand instruction may be linked against `RngPei` and a `RngLib` instance that uses the RNG PPI may be linked against other PEIMs. Signed-off-by: Michael Kubacki --- SecurityPkg/RandomNumberGenerator/RngPei/RngPei.c | 219 +++++++++++++++++++++ .../RandomNumberGenerator/RngPei/RngPei.inf | 37 ++++ .../RandomNumberGenerator/RngPei/RngPei.uni | 12 ++ SecurityPkg/SecurityPkg.dsc | 1 + 4 files changed, 269 insertions(+) create mode 100644 SecurityPkg/RandomNumberGenerator/RngPei/RngPei.c create mode 100644 SecurityPkg/RandomNumberGenerator/RngPei/RngPei.inf create mode 100644 SecurityPkg/RandomNumberGenerator/RngPei/RngPei.uni diff --git a/SecurityPkg/RandomNumberGenerator/RngPei/RngPei.c b/SecurityPkg/RandomNumberGenerator/RngPei/RngPei.c new file mode 100644 index 0000000000..69d6a0d555 --- /dev/null +++ b/SecurityPkg/RandomNumberGenerator/RngPei/RngPei.c @@ -0,0 +1,219 @@ +/** @file + RNG Driver to produce the Random Number Generator PPI. + + The driver uses a platform provided RNG service to produce random numbers. + + Copyright (c) Microsoft Corporation. + Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2015 Hewlett Packard Enterprise Development LP
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include + +/** + Returns information about the random number generation implementation. + + @param[in] This A pointer to the RNG_PPI instance. + @param[in,out] RngAlgorithmListSize On input, the size in bytes of RngAlgorithmList. + On output with a return code of EFI_SUCCESS, the size + in bytes of the data returned in RngAlgorithmList. On output + with a return code of EFI_BUFFER_TOO_SMALL, + the size of RngAlgorithmList required to obtain the list. + @param[out] RngAlgorithmList A caller-allocated memory buffer filled by the driver + with one EFI_RNG_ALGORITHM element for each supported + RNG algorithm. The list must not change across multiple + calls to the same driver. The first algorithm in the list + is the default algorithm for the driver. + + @retval EFI_SUCCESS The RNG algorithm list was returned successfully. + @retval EFI_UNSUPPORTED The services is not supported by this driver. + @retval EFI_DEVICE_ERROR The list of algorithms could not be retrieved due to a + hardware or firmware error. + @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. + @retval EFI_BUFFER_TOO_SMALL The buffer RngAlgorithmList is too small to hold the result. + +**/ +EFI_STATUS +EFIAPI +RngGetInfo ( + IN RNG_PPI *This, + IN OUT UINTN *RngAlgorithmListSize, + OUT EFI_RNG_ALGORITHM *RngAlgorithmList + ) +{ + EFI_STATUS Status; + + if ((This == NULL) || (RngAlgorithmListSize == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Only a single algorithm is supported at this time. The algorithm provided by the + // RngLib instance used with this PEIM. + if (*RngAlgorithmListSize < sizeof (EFI_GUID)) { + *RngAlgorithmListSize = sizeof (EFI_GUID); + return EFI_BUFFER_TOO_SMALL; + } + + if (RngAlgorithmList == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Return algorithm list supported by driver. + // + Status = GetRngGuid (RngAlgorithmList); + if (Status == EFI_SUCCESS) { + DEBUG ((DEBUG_INFO, "[%a] - RNG algorithm successfully retrieved {%g}.\n", __func__, RngAlgorithmList)); + *RngAlgorithmListSize = sizeof (EFI_GUID); + } + + return Status; +} + +/** + Fills a buffer of arbitrary size with random bytes. + + @param[in] Length Size of the buffer, in bytes. + @param[out] RandBuffer Pointer to the buffer to store the random result. + + @retval EFI_SUCCESS Random bytes generation succeeded. + @retval EFI_INVALID_PARAMETER The RandBuffer argument is null. + @retval EFI_NOT_READY Failed to request random bytes. + +**/ +EFI_STATUS +EFIAPI +RngGetBytes ( + IN UINTN Length, + OUT UINT8 *RandBuffer + ) +{ + BOOLEAN IsRandom; + UINT64 TempRand[2]; + + if (RandBuffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + while (Length > 0) { + IsRandom = GetRandomNumber128 (TempRand); + if (!IsRandom) { + return EFI_NOT_READY; + } + + if (Length >= sizeof (TempRand)) { + WriteUnaligned64 ((UINT64 *)RandBuffer, TempRand[0]); + RandBuffer += sizeof (UINT64); + WriteUnaligned64 ((UINT64 *)RandBuffer, TempRand[1]); + RandBuffer += sizeof (UINT64); + Length -= sizeof (TempRand); + } else { + CopyMem (RandBuffer, TempRand, Length); + Length = 0; + } + } + + return EFI_SUCCESS; +} + +/** + Produces and returns an RNG value using either the default or specified RNG algorithm. + + @param[in] This A pointer to the RNG_PPI instance. + @param[in] RngAlgorithm A pointer to the EFI_RNG_ALGORITHM that identifies the RNG + algorithm to use. May be NULL in which case the function will + use its default RNG algorithm. + @param[in] RngValueLength The length in bytes of the memory buffer pointed to by + RngValue. The driver shall return exactly this numbers of bytes. + @param[out] RngValue A caller-allocated memory buffer filled by the driver with the + resulting RNG value. + + @retval EFI_SUCCESS The RNG value was returned successfully. + @retval EFI_UNSUPPORTED The algorithm specified by RngAlgorithm is not supported by + this driver. + @retval EFI_DEVICE_ERROR An RNG value could not be retrieved due to a hardware or + firmware error. + @retval EFI_NOT_READY There is not enough random data available to satisfy the length + requested by RngValueLength. + @retval EFI_INVALID_PARAMETER RngValue is NULL or RngValueLength is zero. + +**/ +EFI_STATUS +EFIAPI +RngGetRNG ( + IN RNG_PPI *This, + IN EFI_RNG_ALGORITHM *RngAlgorithm OPTIONAL, + IN UINTN RngValueLength, + OUT UINT8 *RngValue + ) +{ + EFI_STATUS Status; + UINTN AlgorithmSize; + EFI_RNG_ALGORITHM SupportedAlgorithm; + + if ((RngValueLength == 0) || (RngValue == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (RngAlgorithm != NULL) { + AlgorithmSize = sizeof (SupportedAlgorithm); + Status = RngGetInfo (This, &AlgorithmSize, &SupportedAlgorithm); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + } + + if ((RngAlgorithm == NULL) || CompareGuid (RngAlgorithm, &SupportedAlgorithm)) { + Status = RngGetBytes (RngValueLength, RngValue); + return Status; + } + + // + // Other algorithms are unsupported by this driver. + // + return EFI_UNSUPPORTED; +} + +// +// The Random Number Generator (RNG) PPI +// +RNG_PPI mRngPpi = { + RngGetInfo, + RngGetRNG +}; + +EFI_PEI_PPI_DESCRIPTOR mRngPpiDesc = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiRngPpiGuid, + &mRngPpi +}; + +/** + Entry point. + + @param[in] FileHandle Handle of the file being invoked. + @param[in] PeiServices General purpose services available to every PEIM. + + @retval EFI_SUCCESS The RNG PPI was successfully installed. + @retval Others Returned from PeiServicesInstallPpi(). + +**/ +EFI_STATUS +EFIAPI +RngPeiEntryPoint ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + return PeiServicesInstallPpi (&mRngPpiDesc); +} diff --git a/SecurityPkg/RandomNumberGenerator/RngPei/RngPei.inf b/SecurityPkg/RandomNumberGenerator/RngPei/RngPei.inf new file mode 100644 index 0000000000..135ef96be8 --- /dev/null +++ b/SecurityPkg/RandomNumberGenerator/RngPei/RngPei.inf @@ -0,0 +1,37 @@ +## @file +# Produces the Random Number Generator (RNG) PPI. +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = RngPei + MODULE_UNI_FILE = RngPei.uni + FILE_GUID = D9B35295-D8BB-463E-B7EC-1FD05E5687C1 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + ENTRY_POINT = RngPeiEntryPoint + +[Sources] + RngPei.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + PeimEntryPoint + PeiServicesLib + RngLib + +[Ppis] + gEfiRngPpiGuid ## PRODUCES + +[Depex] + TRUE diff --git a/SecurityPkg/RandomNumberGenerator/RngPei/RngPei.uni b/SecurityPkg/RandomNumberGenerator/RngPei/RngPei.uni new file mode 100644 index 0000000000..c2ac65e954 --- /dev/null +++ b/SecurityPkg/RandomNumberGenerator/RngPei/RngPei.uni @@ -0,0 +1,12 @@ +// /** @file +// Produces the Random Number Generator (RNG) PPI +// +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "Produces the Random Number Generator (RNG) PPI" + +#string STR_MODULE_DESCRIPTION #language en-US "This module produces the Random Number Generator (RNG) PPI." + diff --git a/SecurityPkg/SecurityPkg.dsc b/SecurityPkg/SecurityPkg.dsc index 0b167032ea..ea6a14c328 100644 --- a/SecurityPkg/SecurityPkg.dsc +++ b/SecurityPkg/SecurityPkg.dsc @@ -286,6 +286,7 @@ # # Random Number Generator # + SecurityPkg/RandomNumberGenerator/RngPei/RngPei.inf SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.inf # -- cgit