On Mon, Oct 03, 2022 at 09:34:53 +0200, PierreGondois wrote: > From: Sami Mujawar <sami.muja...@arm.com> > > Bugzilla: 3668 (https://bugzilla.tianocore.org/show_bug.cgi?id=3668) > > The Arm True Random Number Generator Firmware, Interface 1.0, > Platform Design Document > (https://developer.arm.com/documentation/den0098/latest/) > defines an interface between an Operating System (OS) executing > at EL1 and Firmware (FW) exposing a conditioned entropy source > that is provided by a TRNG back end. > > The conditioned entropy, that is provided by the TRNG FW interface, > is commonly used to seed deterministic random number generators. > > This patch adds a TrngLib library that implements the Arm TRNG > firmware interface. > > Signed-off-by: Pierre Gondois <pierre.gond...@arm.com>
Acked-by: Leif Lindholm <quic_llind...@quicinc.com> / Leif > --- > ArmPkg/ArmPkg.dsc | 1 + > ArmPkg/Library/ArmFwTrngLib/ArmFwTrngDefs.h | 50 +++ > ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.c | 388 +++++++++++++++++++ > ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.inf | 29 ++ > 4 files changed, 468 insertions(+) > create mode 100644 ArmPkg/Library/ArmFwTrngLib/ArmFwTrngDefs.h > create mode 100644 ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.c > create mode 100644 ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.inf > > diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc > index 11b473974463..8726989bc73d 100644 > --- a/ArmPkg/ArmPkg.dsc > +++ b/ArmPkg/ArmPkg.dsc > @@ -131,6 +131,7 @@ [Components.common] > > ArmPkg/Library/ArmGenericTimerPhyCounterLib/ArmGenericTimerPhyCounterLib.inf > > ArmPkg/Library/ArmGenericTimerVirtCounterLib/ArmGenericTimerVirtCounterLib.inf > > + ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.inf > ArmPkg/Library/ArmHvcLib/ArmHvcLib.inf > ArmPkg/Library/ArmHvcLibNull/ArmHvcLibNull.inf > ArmPkg/Library/ArmMonitorLib/ArmMonitorLib.inf > diff --git a/ArmPkg/Library/ArmFwTrngLib/ArmFwTrngDefs.h > b/ArmPkg/Library/ArmFwTrngLib/ArmFwTrngDefs.h > new file mode 100644 > index 000000000000..150c89fe7969 > --- /dev/null > +++ b/ArmPkg/Library/ArmFwTrngLib/ArmFwTrngDefs.h > @@ -0,0 +1,50 @@ > +/** @file > + Arm Firmware TRNG definitions. > + > + Copyright (c) 2021 - 2022, Arm Limited. All rights reserved.<BR> > + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > + @par Reference(s): > + - [1] Arm True Random Number Generator Firmware, Interface 1.0, > + Platform Design Document. > + (https://developer.arm.com/documentation/den0098/latest/) > + > + @par Glossary: > + - TRNG - True Random Number Generator > + - FID - Function ID > +**/ > + > +#ifndef ARM_FW_TRNG_DEFS_H_ > +#define ARM_FW_TRNG_DEFS_H_ > + > +#include <IndustryStandard/ArmStdSmc.h> > + > +// Firmware TRNG revision mask and shift > +#define TRNG_REV_MAJOR_MASK 0x7FFF > +#define TRNG_REV_MINOR_MASK 0xFFFF > +#define TRNG_REV_MAJOR_SHIFT 16 > + > +#if defined (MDE_CPU_ARM) > + > +/** FID to use on AArch32 platform to request entropy. > +*/ > +#define FID_TRNG_RND FID_TRNG_RND_AARCH32 > + > +/** Maximum bits of entropy supported on AArch32. > +*/ > +#define MAX_ENTROPY_BITS 96 > +#elif defined (MDE_CPU_AARCH64) > + > +/** FID to use on AArch64 platform to request entropy. > +*/ > +#define FID_TRNG_RND FID_TRNG_RND_AARCH64 > + > +/** Maximum bits of entropy supported on AArch64. > +*/ > +#define MAX_ENTROPY_BITS 192 > +#else > + #error "Firmware TRNG not supported. Unknown chipset." > +#endif > + > +#endif // ARM_FW_TRNG_DEFS_H_ > diff --git a/ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.c > b/ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.c > new file mode 100644 > index 000000000000..df4c59ce7736 > --- /dev/null > +++ b/ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.c > @@ -0,0 +1,388 @@ > +/** @file > + Arm Firmware TRNG interface library. > + > + Copyright (c) 2021 - 2022, Arm Limited. All rights reserved.<BR> > + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > + @par Reference(s): > + - [1] NIST Special Publication 800-90B, Recommendation for the Entropy > + Sources Used for Random Bit Generation. > + (https://csrc.nist.gov/publications/detail/sp/800-90b/final) > + - [2] Arm True Random Number Generator Firmware, Interface 1.0, > + Platform Design Document. > + (https://developer.arm.com/documentation/den0098/latest/) > + > + @par Glossary: > + - TRNG - True Random Number Generator > + - FID - Function ID > +**/ > + > +#include <Base.h> > +#include <Library/ArmLib.h> > +#include <Library/ArmMonitorLib.h> > +#include <Library/BaseMemoryLib.h> > +#include <Library/DebugLib.h> > + > +#include "ArmFwTrngDefs.h" > + > +/** Convert TRNG status codes to RETURN status codes. > + > + @param [in] TrngStatus TRNG status code. > + > + @retval RETURN_SUCCESS Success. > + @retval RETURN_UNSUPPORTED Function not implemented or > + negative return code. > + @retval RETURN_INVALID_PARAMETER A parameter is invalid. > + @retval RETURN_NOT_READY No Entropy available. > +**/ > +STATIC > +RETURN_STATUS > +TrngStatusToReturnStatus ( > + IN INT32 TrngStatus > + ) > +{ > + switch (TrngStatus) { > + case TRNG_STATUS_NOT_SUPPORTED: > + return RETURN_UNSUPPORTED; > + > + case TRNG_STATUS_INVALID_PARAMETER: > + return RETURN_INVALID_PARAMETER; > + > + case TRNG_STATUS_NO_ENTROPY: > + return RETURN_NOT_READY; > + > + case TRNG_STATUS_SUCCESS: > + return RETURN_SUCCESS; > + > + default: > + if (TrngStatus < 0) { > + return RETURN_UNSUPPORTED; > + } > + > + return RETURN_SUCCESS; > + } > +} > + > +/** Get the version of the TRNG backend. > + > + A TRNG may be implemented by the system firmware, in which case this > + function shall return the version of the TRNG backend. > + The implementation must return NOT_SUPPORTED if a Back end is not present. > + > + @param [out] MajorRevision Major revision. > + @param [out] MinorRevision Minor revision. > + > + @retval RETURN_SUCCESS The function completed successfully. > + @retval RETURN_INVALID_PARAMETER Invalid parameter. > + @retval RETURN_UNSUPPORTED Backend not present. > +**/ > +RETURN_STATUS > +EFIAPI > +GetTrngVersion ( > + OUT UINT16 *MajorRevision, > + OUT UINT16 *MinorRevision > + ) > +{ > + RETURN_STATUS Status; > + ARM_MONITOR_ARGS Parameters; > + INT32 Revision; > + > + if ((MajorRevision == NULL) || (MinorRevision == NULL)) { > + return RETURN_INVALID_PARAMETER; > + } > + > + ZeroMem (&Parameters, sizeof (Parameters)); > + > + Parameters.Arg0 = FID_TRNG_VERSION; > + ArmMonitorCall (&Parameters); > + > + Revision = (INT32)Parameters.Arg0; > + Status = TrngStatusToReturnStatus (Revision); > + if (RETURN_ERROR (Status)) { > + return Status; > + } > + > + *MinorRevision = (Revision & TRNG_REV_MINOR_MASK); > + *MajorRevision = ((Revision >> TRNG_REV_MAJOR_SHIFT) & > TRNG_REV_MAJOR_MASK); > + return RETURN_SUCCESS; > +} > + > +/** Get the features supported by the TRNG backend. > + > + The caller can determine if functions defined in the TRNG ABI are > + present in the ABI implementation. > + > + @param [in] FunctionId Function Id. > + @param [out] Capability Function specific capability if present. > + > + @retval RETURN_SUCCESS The function completed successfully. > + @retval RETURN_INVALID_PARAMETER Invalid parameter. > + @retval RETURN_UNSUPPORTED Function not implemented. > +**/ > +STATIC > +RETURN_STATUS > +EFIAPI > +GetTrngFeatures ( > + IN CONST UINT32 FunctionId, > + OUT UINT32 *Capability OPTIONAL > + ) > +{ > + ARM_MONITOR_ARGS Parameters; > + RETURN_STATUS Status; > + > + ZeroMem (&Parameters, sizeof (Parameters)); > + > + Parameters.Arg0 = FID_TRNG_FEATURES; > + Parameters.Arg1 = FunctionId; > + ArmMonitorCall (&Parameters); > + > + Status = TrngStatusToReturnStatus (Parameters.Arg0); > + if (RETURN_ERROR (Status)) { > + return Status; > + } > + > + if (Capability != NULL) { > + *Capability = (UINT32)Parameters.Arg0; > + } > + > + return RETURN_SUCCESS; > +} > + > +/** Get the UUID of the TRNG backend. > + > + A TRNG may be implemented by the system firmware, in which case this > + function shall return the UUID of the TRNG backend. > + Returning the TRNG UUID is optional and if not implemented, > RETURN_UNSUPPORTED > + shall be returned. > + > + Note: The caller must not rely on the returned UUID as a trustworthy TRNG > + Back end identity > + > + @param [out] Guid UUID of the TRNG backend. > + > + @retval RETURN_SUCCESS The function completed successfully. > + @retval RETURN_INVALID_PARAMETER Invalid parameter. > + @retval RETURN_UNSUPPORTED Function not implemented. > +**/ > +RETURN_STATUS > +EFIAPI > +GetTrngUuid ( > + OUT GUID *Guid > + ) > +{ > + ARM_MONITOR_ARGS Parameters; > + > + if (Guid == NULL) { > + return RETURN_INVALID_PARAMETER; > + } > + > + ZeroMem (&Parameters, sizeof (Parameters)); > + > + Parameters.Arg0 = FID_TRNG_GET_UUID; > + ArmMonitorCall (&Parameters); > + > + // Only invalid value is TRNG_STATUS_NOT_SUPPORTED (-1). > + if ((INT32)Parameters.Arg0 == TRNG_STATUS_NOT_SUPPORTED) { > + return TrngStatusToReturnStatus ((INT32)Parameters.Arg0); > + } > + > + Guid->Data1 = (Parameters.Arg0 & MAX_UINT32); > + Guid->Data2 = (Parameters.Arg1 & MAX_UINT16); > + Guid->Data3 = ((Parameters.Arg1 >> 16) & MAX_UINT16); > + > + Guid->Data4[0] = (Parameters.Arg2 & MAX_UINT8); > + Guid->Data4[1] = ((Parameters.Arg2 >> 8) & MAX_UINT8); > + Guid->Data4[2] = ((Parameters.Arg2 >> 16) & MAX_UINT8); > + Guid->Data4[3] = ((Parameters.Arg2 >> 24) & MAX_UINT8); > + > + Guid->Data4[4] = (Parameters.Arg3 & MAX_UINT8); > + Guid->Data4[5] = ((Parameters.Arg3 >> 8) & MAX_UINT8); > + Guid->Data4[6] = ((Parameters.Arg3 >> 16) & MAX_UINT8); > + Guid->Data4[7] = ((Parameters.Arg3 >> 24) & MAX_UINT8); > + > + DEBUG ((DEBUG_INFO, "FW-TRNG: UUID %g\n", Guid)); > + > + return RETURN_SUCCESS; > +} > + > +/** Returns maximum number of entropy bits that can be returned in a single > + call. > + > + @return Returns the maximum number of Entropy bits that can be returned > + in a single call to GetTrngEntropy(). > +**/ > +UINTN > +EFIAPI > +GetTrngMaxSupportedEntropyBits ( > + VOID > + ) > +{ > + return MAX_ENTROPY_BITS; > +} > + > +/** Returns N bits of conditioned entropy. > + > + See [1] Section 2.3.1 GetEntropy: An Interface to the Entropy Source > + GetEntropy > + Input: > + bits_of_entropy: the requested amount of entropy > + Output: > + entropy_bitstring: The string that provides the requested entropy. > + status: A Boolean value that is TRUE if the request has been satisfied, > + and is FALSE otherwise. > + > + @param [in] EntropyBits Number of entropy bits requested. > + @param [in] BufferSize Size of the Buffer in bytes. > + @param [out] Buffer Buffer to return the entropy bits. > + > + @retval RETURN_SUCCESS The function completed successfully. > + @retval RETURN_INVALID_PARAMETER Invalid parameter. > + @retval RETURN_UNSUPPORTED Function not implemented. > + @retval RETURN_BAD_BUFFER_SIZE Buffer size is too small. > + @retval RETURN_NOT_READY No Entropy available. > +**/ > +RETURN_STATUS > +EFIAPI > +GetTrngEntropy ( > + IN UINTN EntropyBits, > + IN UINTN BufferSize, > + OUT UINT8 *Buffer > + ) > +{ > + RETURN_STATUS Status; > + ARM_MONITOR_ARGS Parameters; > + UINTN EntropyBytes; > + UINTN LastValidBits; > + UINTN BytesToClear; > + UINTN EntropyData[3]; > + > + if ((EntropyBits == 0) || > + (EntropyBits > MAX_ENTROPY_BITS) || > + (Buffer == NULL)) > + { > + return RETURN_INVALID_PARAMETER; > + } > + > + EntropyBytes = (EntropyBits + 7) >> 3; > + if (EntropyBytes > BufferSize) { > + return RETURN_BAD_BUFFER_SIZE; > + } > + > + ZeroMem (Buffer, BufferSize); > + ZeroMem (&Parameters, sizeof (Parameters)); > + > + Parameters.Arg0 = FID_TRNG_RND; > + Parameters.Arg1 = EntropyBits; > + ArmMonitorCall (&Parameters); > + > + Status = TrngStatusToReturnStatus ((INT32)Parameters.Arg0); > + if (RETURN_ERROR (Status)) { > + return Status; > + } > + > + // The entropy data is returned in the Parameters.Arg<3..1> > + // With the lower order bytes in Parameters.Arg3 and the higher > + // order bytes being stored in Parameters.Arg1. > + EntropyData[0] = Parameters.Arg3; > + EntropyData[1] = Parameters.Arg2; > + EntropyData[2] = Parameters.Arg1; > + > + CopyMem (Buffer, EntropyData, EntropyBytes); > + > + // Mask off any unused top bytes, in accordance with specification. > + BytesToClear = BufferSize - EntropyBytes; > + if (BytesToClear != 0) { > + ZeroMem (&Buffer[EntropyBytes], BytesToClear); > + } > + > + // Clear the unused MSB bits of the last byte. > + LastValidBits = EntropyBits & 0x7; > + if (LastValidBits != 0) { > + Buffer[EntropyBytes - 1] &= (0xFF >> (8 - LastValidBits)); > + } > + > + return Status; > +} > + > +/** The constructor checks that the FW-TRNG interface is supported > + by the host firmware. > + > + It will ASSERT() if FW-TRNG is not supported. > + It will always return RETURN_SUCCESS. > + > + @retval RETURN_SUCCESS The constructor always returns RETURN_SUCCESS. > +**/ > +RETURN_STATUS > +EFIAPI > +ArmFwTrngLibConstructor ( > + VOID > + ) > +{ > + ARM_MONITOR_ARGS Parameters; > + RETURN_STATUS Status; > + UINT16 MajorRev; > + UINT16 MinorRev; > + GUID Guid; > + > + ZeroMem (&Parameters, sizeof (Parameters)); > + > + Parameters.Arg0 = SMCCC_VERSION; > + ArmMonitorCall (&Parameters); > + Status = TrngStatusToReturnStatus ((INT32)Parameters.Arg0); > + if (RETURN_ERROR (Status)) { > + ASSERT_RETURN_ERROR (Status); > + goto ErrorHandler; > + } > + > + // Cf [1] s2.1.3 'Caller responsibilities', > + // SMCCC version must be greater or equal than 1.1 > + if ((INT32)Parameters.Arg0 < 0x10001) { > + ASSERT_RETURN_ERROR (RETURN_UNSUPPORTED); > + goto ErrorHandler; > + } > + > + Status = GetTrngVersion (&MajorRev, &MinorRev); > + if (RETURN_ERROR (Status)) { > + ASSERT_RETURN_ERROR (Status); > + goto ErrorHandler; > + } > + > + // Check that the required features are present. > + Status = GetTrngFeatures (FID_TRNG_RND, NULL); > + if (RETURN_ERROR (Status)) { > + ASSERT_RETURN_ERROR (Status); > + goto ErrorHandler; > + } > + > + // Check if TRNG UUID is supported and if so trace the GUID. > + Status = GetTrngFeatures (FID_TRNG_GET_UUID, NULL); > + if (RETURN_ERROR (Status)) { > + ASSERT_RETURN_ERROR (Status); > + goto ErrorHandler; > + } > + > + DEBUG_CODE_BEGIN (); > + > + Status = GetTrngUuid (&Guid); > + if (RETURN_ERROR (Status)) { > + ASSERT_RETURN_ERROR (Status); > + goto ErrorHandler; > + } > + > + DEBUG (( > + DEBUG_INFO, > + "FW-TRNG: Version %d.%d, GUID {%g}\n", > + MajorRev, > + MinorRev, > + Guid > + )); > + > + DEBUG_CODE_END (); > + > + return RETURN_SUCCESS; > + > +ErrorHandler: > + DEBUG ((DEBUG_ERROR, "ArmFwTrngLib could not be correctly > initialized.\n")); > + return RETURN_SUCCESS; > +} > diff --git a/ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.inf > b/ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.inf > new file mode 100644 > index 000000000000..ae3eb9bcfe7d > --- /dev/null > +++ b/ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.inf > @@ -0,0 +1,29 @@ > +## @file > +# Arm Firmware TRNG interface library. > +# > +# Copyright (c) 2021 - 2022, Arm Limited. All rights reserved.<BR> > +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +## > + > +[Defines] > + INF_VERSION = 1.29 > + BASE_NAME = ArmFwTrngLib > + FILE_GUID = 10DE97C9-28E4-4C9B-A53E-8D7D1B0DD4E0 > + VERSION_STRING = 1.0 > + MODULE_TYPE = BASE > + LIBRARY_CLASS = TrngLib > + CONSTRUCTOR = ArmFwTrngLibConstructor > + > +[Sources] > + ArmFwTrngDefs.h > + ArmFwTrngLib.c > + > +[Packages] > + ArmPkg/ArmPkg.dec > + MdePkg/MdePkg.dec > + > +[LibraryClasses] > + ArmMonitorLib > + BaseLib > + BaseMemoryLib > -- > 2.25.1 > > > > > > -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#94752): https://edk2.groups.io/g/devel/message/94752 Mute This Topic: https://groups.io/mt/94085853/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-