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: Sami Mujawar <sami.muja...@arm.com> --- Notes: v2: - MdePkg\Include\Library\TrngLib.h is base type [LIMING] library. It can use RETURN_STATUS instead of EFI_STATUS. - Replaced EFI_STATUS with RETURN_STATUS. [SAMI] - MdePkg\Include\Library\TrngLib.h API parameter [LIMING] doesn't require CONST. CONST means the value specified by the input pointer will not be changed in API implementation. - Removed the use of constant pointers in the [SAMI] TRNG API. ArmPkg/ArmPkg.dsc | 1 + ArmPkg/Library/ArmFwTrngLib/ArmFwTrngDefs.h | 64 +++ ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.c | 483 ++++++++++++++++++++ ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.inf | 34 ++ 4 files changed, 582 insertions(+) diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc index 59fd8f295d4f614cc68ee1021e691f94e279ab81..23df68c5eb53df11de5d96bde4949f3c833c9b2c 100644 --- a/ArmPkg/ArmPkg.dsc +++ b/ArmPkg/ArmPkg.dsc @@ -156,6 +156,7 @@ [Components.common] ArmPkg/Drivers/ArmCrashDumpDxe/ArmCrashDumpDxe.inf ArmPkg/Drivers/ArmScmiDxe/ArmScmiDxe.inf + ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.inf ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClassDxe.inf ArmPkg/Universal/Smbios/SmbiosMiscDxe/SmbiosMiscDxe.inf ArmPkg/Universal/Smbios/OemMiscLibNull/OemMiscLibNull.inf diff --git a/ArmPkg/Library/ArmFwTrngLib/ArmFwTrngDefs.h b/ArmPkg/Library/ArmFwTrngLib/ArmFwTrngDefs.h new file mode 100644 index 0000000000000000000000000000000000000000..42236e743d972df0df205b1565496afeff5785f3 --- /dev/null +++ b/ArmPkg/Library/ArmFwTrngLib/ArmFwTrngDefs.h @@ -0,0 +1,64 @@ +/** @file + Arm Firmware TRNG definitions. + + Copyright (c) 2021, 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_ + +// Firmware TRNG interface Function IDs +#define FID_TRNG_VERSION 0x84000050 +#define FID_TRNG_FEATURES 0x84000051 +#define FID_TRNG_GET_UUID 0x84000052 +#define FID_TRNG_RND_AARCH32 0x84000053 +#define FID_TRNG_RND_AARCH64 0xC4000053 + +// Firmware TRNG revision mask and shift +#define TRNG_REV_MAJOR_MASK 0x7FFF +#define TRNG_REV_MINOR_MASK 0xFFFF +#define TRNG_REV_MAJOR_SHIFT 16 +#define TRNG_REV_MINOR_SHIFT 0 + +// Firmware TRNG status codes +#define TRNG_STATUS_SUCCESS (INT32)(0) +#define TRNG_NOT_SUPPORTED (INT32)(-1) +#define TRNG_INVALID_PARAMETER (INT32)(-2) +#define TRNG_NO_ENTROPY (INT32)(-3) + +#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 + +/** Typedef for SMC or HVC arguments. +*/ +typedef ARM_SMC_ARGS ARM_MONITOR_ARGS; + +#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 0000000000000000000000000000000000000000..314e7ffbc232ae90bbb77306f9c7113ce63012c8 --- /dev/null +++ b/ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.c @@ -0,0 +1,483 @@ +/** @file + Arm Firmware TRNG interface library. + + Copyright (c) 2021, 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/) + - [2] NIST Special Publication 800-90A Revision 1, June 2015, Recommendation + for Random Number Generation Using Deterministic Random Bit Generators. + (https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final) + - [3] 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) + - [4] (Second Draft) NIST Special Publication 800-90C, Recommendation for + Random Bit Generator (RBG) Constructions. + (https://csrc.nist.gov/publications/detail/sp/800-90c/draft) + + @par Glossary: + - TRNG - True Random Number Generator + - FID - Function ID +**/ + +#include <Base.h> +#include <Library/ArmHvcLib.h> +#include <Library/ArmLib.h> +#include <Library/ArmSmcLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> + +#include "ArmFwTrngDefs.h" + +/** Convert TRNG status codes to EFI status codes. + + @param [in] TrngStatus TRNG status code. + + @retval RETURN_SUCCESS Success. + @retval RETURN_UNSUPPORTED Function not implemented. + @retval RETURN_INVALID_PARAMETER A parameter is invalid. + @retval RETURN_NOT_READY No Entropy available. +**/ +STATIC +RETURN_STATUS +TrngStatusToEfiStatus ( + IN INT32 TrngStatus + ) +{ + switch (TrngStatus) { + case TRNG_NOT_SUPPORTED: + return RETURN_UNSUPPORTED; + + case TRNG_INVALID_PARAMETER: + return RETURN_INVALID_PARAMETER; + + case TRNG_NO_ENTROPY: + return RETURN_NOT_READY; + + case TRNG_STATUS_SUCCESS: + default: + return RETURN_SUCCESS; + } +} + +/** Invoke the monitor call using the appropriate conduit. + If PcdMonitorConduitHvc is TRUE use the HVC conduit else use SMC conduit. + + @param [in, out] Args Arguments passed to and returned from the monitor. + + @return VOID +**/ +STATIC +VOID +ArmCallMonitor ( + IN OUT ARM_MONITOR_ARGS *Args + ) +{ + if (FeaturePcdGet (PcdMonitorConduitHvc)) { + ArmCallHvc ((ARM_HVC_ARGS*)Args); + } else { + ArmCallSmc ((ARM_SMC_ARGS*)Args); + } +} + +/** 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)); + + /* + Cf. [1], 2.1 TRNG_VERSION + Function ID (W0) 0x8400_0050 + Parameters + W1-W7 Reserved (MBZ) + Returns + Success (W0 > 0) W0[31] MBZ + W0[30:16] Major revision + W0[15:0] Minor revision + W1 - W3 Reserved (MBZ) + Error (W0 < 0) + NOT_SUPPORTED Function not implemented + */ + Parameters.Arg0 = FID_TRNG_VERSION; + ArmCallMonitor (&Parameters); + + Revision = (INT32)Parameters.Arg0; + // Convert status codes to EFI status codes. + Status = TrngStatusToEfiStatus (Revision); + if (EFI_ERROR (Status)) { + return Status; + } + + *MinorRevision = (Revision & TRNG_REV_MINOR_MASK); + *MajorRevision = ((Revision >> TRNG_REV_MAJOR_SHIFT) & TRNG_REV_MAJOR_MASK); + return RETURN_SUCCESS; +} + +#ifndef MDEPKG_NDEBUG +/** 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 + otherwise Zero is returned. + + @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; + + ZeroMem (&Parameters, sizeof (Parameters)); + + /* + Cf. [1], Section 2.2 TRNG_FEATURES + Function ID (W0) 0x8400_0051 + Parameters + W1 trng_func_id + W2-W7 Reserved (MBZ) + Returns + Success (W0 >= 0) + SUCCESS Function is implemented. + > 0 Function is implemented and + has specific capabilities, + see function definition. + Error (W0 < 0) + NOT_SUPPORTED Function with FID=trng_func_id + is not implemented + */ + Parameters.Arg0 = FID_TRNG_FEATURES; + Parameters.Arg1 = FunctionId; + ArmCallMonitor (&Parameters); + if (Parameters.Arg0 < TRNG_STATUS_SUCCESS) { + return RETURN_UNSUPPORTED; + } + + if (Capability != NULL) { + *Capability = Parameters.Arg0; + } + + return RETURN_SUCCESS; +} +#endif //MDEPKG_NDEBUG + +/** 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 + ) +{ + RETURN_STATUS Status; + ARM_MONITOR_ARGS Parameters; + + ZeroMem (&Parameters, sizeof (Parameters)); + + /* + Cf. [1], Section 2.3 TRNG_GET_UUID + Function ID (W0) 0x8400_0052 + Parameters + W1-W7 Reserved (MBZ) + Returns + Success (W0 != -1) + W0 UUID[31:0] + W1 UUID[63:32] + W2 UUID[95:64] + W3 UUID[127:96] + Error (W0 = -1) + W0 NOT_SUPPORTED + */ + Parameters.Arg0 = FID_TRNG_GET_UUID; + ArmCallMonitor (&Parameters); + + // Convert status codes to EFI status codes. + Status = TrngStatusToEfiStatus ((INT32)Parameters.Arg0); + if (EFI_ERROR (Status)) { + return Status; + } + + 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 GetEntropy(). +**/ +UINTN +EFIAPI +GetTrngMaxSupportedEntropyBits ( + VOID + ) +{ + return MAX_ENTROPY_BITS; +} + +/** Returns N bits of conditioned entropy. + + See [3] 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. + + Note: In this implementation this function returns a status code instead + of a boolean value. + This is also compatible with the definition of Get_Entropy, see [2] + Section 7.4 Entropy Source Calls. + (status, entropy_bitstring) = Get_Entropy ( + requested_entropy, + max_length + ) + + @param [in] EntropyBits Number of entropy bits requested. + @param [out] Buffer Buffer to return the entropy bits. + @param [in] BufferSize Size of the Buffer in bytes. + + @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 +GetEntropy ( + IN CONST UINTN EntropyBits, + OUT UINT8 *Buffer, + IN CONST UINTN BufferSize + ) +{ + RETURN_STATUS Status; + ARM_MONITOR_ARGS Parameters; + UINTN EntropyBytes; + UINTN LastValidBits; + UINTN ArgSelector; + UINTN BytesToClear; + + // [1] Section 2.4.3 Caller responsibilities. + // The caller cannot request more than MAX_BITS bits of conditioned + // entropy per call. + if ((EntropyBits == 0) || (EntropyBits > MAX_ENTROPY_BITS)) { + return RETURN_INVALID_PARAMETER; + } + + EntropyBytes = (EntropyBits + 7) >> 3; + if (EntropyBytes > BufferSize) { + return RETURN_BAD_BUFFER_SIZE; + } + + ZeroMem (Buffer, BufferSize); + ZeroMem (&Parameters, sizeof (Parameters)); + + /* + Cf. [1], Section 2.4 TRNG_RND + Function ID (W0) 0x8400_0053 + 0xC400_0053 + SMC32 Parameters + W1 N bits of entropy (1 6 N 6 96) + W2-W7 Reserved (MBZ) + SMC64 Parameters + X1 N bits of entropy (1 6 N 6 192) + X2-X7 Reserved (MBZ) + SMC32 Returns + Success (W0 = 0): + W0 MBZ + W1 Entropy[95:64] + W2 Entropy[63:32] + W3 Entropy[31:0] + Error (W0 < 0) + W0 NOT_SUPPORTED + NO_ENTROPY + INVALID_PARAMETERS + W1 - W3 Reserved (MBZ) + SMC64 Returns + Success (X0 = 0): + X0 MBZ + X1 Entropy[191:128] + X2 Entropy[127:64] + X3 Entropy[63:0] + Error (X0 < 0) + X0 NOT_SUPPORTED + NO_ENTROPY + INVALID_PARAMETERS + X1 - X3 Reserved (MBZ) + */ + Parameters.Arg0 = FID_TRNG_RND; + Parameters.Arg1 = EntropyBits; + ArmCallMonitor (&Parameters); + + // Convert status codes to EFI status codes. + Status = TrngStatusToEfiStatus ((INT32)Parameters.Arg0); + if (EFI_ERROR (Status)) { + return Status; + } + + // Extract Data + // ArgSelector = ((EntropyBytes + 3) >> 2); for AArch32 + // ArgSelector = ((EntropyBytes + 7) >> 3); for AArch64 + // ((sizeof (UINTN) >> 2) + 1) is 3 or 2 depending on size of UINTN + ArgSelector = ((EntropyBytes + (sizeof (UINTN) - 1)) >> + ((sizeof (UINTN) >> 2) + 1)); + + switch (ArgSelector) { + case 3: + CopyMem (&Buffer[(sizeof (UINTN) * 2)], &Parameters.Arg1, sizeof (UINTN)); + + case 2: + CopyMem (&Buffer[sizeof (UINTN)], &Parameters.Arg2, sizeof (UINTN)); + + case 1: + CopyMem (&Buffer[0], &Parameters.Arg3, sizeof (UINTN)); + break; + + default: + ASSERT (0); + return RETURN_INVALID_PARAMETER; + } // switch + + + // [1] Section 2.4.3 Caller responsibilities. + // The caller must ensure that only the value in Entropy[N-1:0] is consumed + // and that the remaining bits in Entropy[MAX_BITS-1:N] are ignored. + // Therefore, Clear the unused upper bytes. + BytesToClear = (sizeof (UINTN) * ArgSelector) - 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 + ) +{ + RETURN_STATUS Status; + UINT16 MajorRev; + UINT16 MinorRev; + GUID Guid; + + Status = GetTrngVersion (&MajorRev, &MinorRev); + if (EFI_ERROR (Status)) { + return RETURN_SUCCESS; + } + +#ifndef MDEPKG_NDEBUG + // Check that the required features are present. + Status = GetTrngFeatures (FID_TRNG_RND, NULL); + if (EFI_ERROR (Status)) { + return RETURN_SUCCESS; + } + + // Check if TRNG UUID is supported and if so trace the GUID. + Status = GetTrngFeatures (FID_TRNG_GET_UUID, NULL); + if (EFI_ERROR (Status)) { + return RETURN_SUCCESS; + } +#endif + + Status = GetTrngUuid (&Guid); + if (EFI_ERROR (Status)) { + return RETURN_SUCCESS; + } + + DEBUG (( + DEBUG_INFO, + "FW-TRNG: Version %d.%d, GUID {%g}\n", + MajorRev, + MinorRev, + Guid + )); + + return RETURN_SUCCESS; +} diff --git a/ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.inf b/ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.inf new file mode 100644 index 0000000000000000000000000000000000000000..4b2c58251fbe8fbcb5af308736db014e8d954720 --- /dev/null +++ b/ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.inf @@ -0,0 +1,34 @@ +## @file +# Arm Firmware TRNG interface library. +# +# Copyright (c) 2021, Arm Limited. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x0001001B + 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] + ArmSmcLib + ArmHvcLib + BaseLib + BaseMemoryLib + +[Pcd] + gArmTokenSpaceGuid.PcdMonitorConduitHvc + -- 'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)' -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#83777): https://edk2.groups.io/g/devel/message/83777 Mute This Topic: https://groups.io/mt/87092734/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-