Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MdePkg/DxeRngLib: Refactoring and improvements #6158

Merged
merged 5 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
204 changes: 169 additions & 35 deletions MdePkg/Library/DxeRngLib/DxeRngLib.c
Original file line number Diff line number Diff line change
@@ -1,17 +1,136 @@
/** @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 <Uefi.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/RngLib.h>
#include <Protocol/Rng.h>

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[] = {
#ifdef MDE_CPU_AARCH64
{
&gEfiRngAlgorithmArmRndr, // unspecified SP800-90A DRBG (through RNDR instr.)
"ARM-RNDR",
FALSE,
},
#endif
{
&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:

Expand All @@ -32,55 +151,70 @@ 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;
if (mRngProtocol == NULL) {
return EFI_NOT_FOUND;
}

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;
// 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, &gEfiRngAlgorithmSp80090Hmac256Guid, BufferSize, Buffer);
DEBUG ((DEBUG_INFO, "%a: GetRNG algorithm HMAC-256 - Status = %r\n", __func__, Status));
if (!EFI_ERROR (Status)) {
return Status;
}

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;
// 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;
}
}

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;
}

// If all the other methods have failed, use the default method from the RngProtocol
Status = RngProtocol->GetRNG (RngProtocol, NULL, BufferSize, Buffer);
DEBUG ((DEBUG_INFO, "%a: GetRNG algorithm default - Status = %r\n", __func__, Status));
if (!EFI_ERROR (Status)) {
return Status;
if (!PcdGetBool (PcdEnforceSecureRngAlgorithms)) {
// If all the other methods have failed, use the default method from the RngProtocol
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()
Expand Down
8 changes: 8 additions & 0 deletions MdePkg/Library/DxeRngLib/DxeRngLib.inf
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -24,6 +25,7 @@

[LibraryClasses]
DebugLib
MemoryAllocationLib
UefiBootServicesTableLib

[Protocols]
Expand All @@ -37,3 +39,9 @@
gEfiRngAlgorithmSp80090Hash256Guid
gEfiRngAlgorithmSp80090Hmac256Guid
gEfiRngAlgorithmRaw

[Guids.AARCH64]
gEfiRngAlgorithmArmRndr

[FixedPcd]
gEfiMdePkgTokenSpaceGuid.PcdEnforceSecureRngAlgorithms ## CONSUMES
6 changes: 6 additions & 0 deletions MdePkg/MdePkg.dec
Original file line number Diff line number Diff line change
Expand Up @@ -2266,6 +2266,12 @@
## This PCD specifies the interrupt vector for stack cookie check failures
gEfiMdePkgTokenSpaceGuid.PcdStackCookieExceptionVector|0x42|UINT8|0x30001019

## Enforces the use of Secure UEFI spec defined RNG algorithms.
# TRUE - Enforce the use of Secure UEFI spec defined RNG algorithms.
# FALSE - Do not enforce and depend on the default implementation of RNG algorithm from the provider.
# @Prompt Enforce the use of Secure UEFI spec defined RNG algorithms.
gEfiMdePkgTokenSpaceGuid.PcdEnforceSecureRngAlgorithms|TRUE|BOOLEAN|0x1000000D

[PcdsFixedAtBuild,PcdsPatchableInModule]
## Indicates the maximum length of unicode string used in the following
# BaseLib functions: StrLen(), StrSize(), StrCmp(), StrnCmp(), StrCpy(), StrnCpy()<BR><BR>
Expand Down
2 changes: 1 addition & 1 deletion NetworkPkg/Library/DxeNetLib/DxeNetLib.inf
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
gEfiRngProtocolGuid ## CONSUMES

[FixedPcd]
gEfiNetworkPkgTokenSpaceGuid.PcdEnforceSecureRngAlgorithms ## CONSUMES
gEfiMdePkgTokenSpaceGuid.PcdEnforceSecureRngAlgorithms ## CONSUMES

[Depex]
gEfiRngProtocolGuid
6 changes: 0 additions & 6 deletions NetworkPkg/NetworkPkg.dec
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,6 @@
# @Prompt Indicates whether SnpDxe creates event for ExitBootServices() call.
gEfiNetworkPkgTokenSpaceGuid.PcdSnpCreateExitBootServicesEvent|TRUE|BOOLEAN|0x1000000C

## Enforces the use of Secure UEFI spec defined RNG algorithms for all network connections.
# TRUE - Enforce the use of Secure UEFI spec defined RNG algorithms.
# FALSE - Do not enforce and depend on the default implementation of RNG algorithm from the provider.
# @Prompt Enforce the use of Secure UEFI spec defined RNG algorithms.
gEfiNetworkPkgTokenSpaceGuid.PcdEnforceSecureRngAlgorithms|TRUE|BOOLEAN|0x1000000D

[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
## IPv6 DHCP Unique Identifier (DUID) Type configuration (From RFCs 3315 and 6355).
# 01 = DUID Based on Link-layer Address Plus Time [DUID-LLT]
Expand Down
Loading