From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.web08.6887.1666099845641838256 for ; Tue, 18 Oct 2022 06:30:45 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: arm.com, ip: 217.140.110.172, mailfrom: pierre.gondois@arm.com) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 874AC2454; Tue, 18 Oct 2022 06:30:51 -0700 (PDT) Received: from pierre123.arm.com (pierre123.nice.arm.com [10.34.100.128]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id CAD483F792; Tue, 18 Oct 2022 06:30:43 -0700 (PDT) From: "PierreGondois" To: devel@edk2.groups.io Cc: Sami Mujawar , Leif Lindholm , Ard Biesheuvel , Rebecca Cran , Michael D Kinney , Liming Gao , Jiewen Yao , Jian J Wang Subject: [PATCH v8 09/19] ArmPkg/TrngLib: Add Arm Firmware TRNG library Date: Tue, 18 Oct 2022 15:20:42 +0200 Message-Id: <20221018132052.1359530-10-Pierre.Gondois@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20221018132052.1359530-1-Pierre.Gondois@arm.com> References: <20221018132052.1359530-1-Pierre.Gondois@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Sami Mujawar Bugzilla: 3668 (https://bugzilla.tianocore.org/show_bug.cgi?id=3D3668) 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. Acked-by: Leif Lindholm Signed-off-by: Pierre Gondois --- 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/ArmGenericTimerPhyCounterL= ib.inf ArmPkg/Library/ArmGenericTimerVirtCounterLib/ArmGenericTimerVirtCounte= rLib.inf =20 + 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..8038a968b50f --- /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.
+ + 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 + +// 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 ARM_SMC_ID_TRNG_RND ARM_SMC_ID_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 ARM_SMC_ID_TRNG_RND ARM_SMC_ID_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..426a6f221d78 --- /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.
+ + 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 +#include +#include +#include +#include + +#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 pres= ent. + + @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 =3D=3D NULL) || (MinorRevision =3D=3D NULL)) { + return RETURN_INVALID_PARAMETER; + } + + ZeroMem (&Parameters, sizeof (Parameters)); + + Parameters.Arg0 =3D ARM_SMC_ID_TRNG_VERSION; + ArmMonitorCall (&Parameters); + + Revision =3D (INT32)Parameters.Arg0; + Status =3D TrngStatusToReturnStatus (Revision); + if (RETURN_ERROR (Status)) { + return Status; + } + + *MinorRevision =3D (Revision & TRNG_REV_MINOR_MASK); + *MajorRevision =3D ((Revision >> TRNG_REV_MAJOR_SHIFT) & TRNG_REV_MAJO= R_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 presen= t. + + @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 =3D ARM_SMC_ID_TRNG_FEATURES; + Parameters.Arg1 =3D FunctionId; + ArmMonitorCall (&Parameters); + + Status =3D TrngStatusToReturnStatus (Parameters.Arg0); + if (RETURN_ERROR (Status)) { + return Status; + } + + if (Capability !=3D NULL) { + *Capability =3D (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_UNS= UPPORTED + shall be returned. + + Note: The caller must not rely on the returned UUID as a trustworthy T= RNG + 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 =3D=3D NULL) { + return RETURN_INVALID_PARAMETER; + } + + ZeroMem (&Parameters, sizeof (Parameters)); + + Parameters.Arg0 =3D ARM_SMC_ID_TRNG_GET_UUID; + ArmMonitorCall (&Parameters); + + // Only invalid value is TRNG_STATUS_NOT_SUPPORTED (-1). + if ((INT32)Parameters.Arg0 =3D=3D TRNG_STATUS_NOT_SUPPORTED) { + return TrngStatusToReturnStatus ((INT32)Parameters.Arg0); + } + + Guid->Data1 =3D (Parameters.Arg0 & MAX_UINT32); + Guid->Data2 =3D (Parameters.Arg1 & MAX_UINT16); + Guid->Data3 =3D ((Parameters.Arg1 >> 16) & MAX_UINT16); + + Guid->Data4[0] =3D (Parameters.Arg2 & MAX_UINT8); + Guid->Data4[1] =3D ((Parameters.Arg2 >> 8) & MAX_UINT8); + Guid->Data4[2] =3D ((Parameters.Arg2 >> 16) & MAX_UINT8); + Guid->Data4[3] =3D ((Parameters.Arg2 >> 24) & MAX_UINT8); + + Guid->Data4[4] =3D (Parameters.Arg3 & MAX_UINT8); + Guid->Data4[5] =3D ((Parameters.Arg3 >> 8) & MAX_UINT8); + Guid->Data4[6] =3D ((Parameters.Arg3 >> 16) & MAX_UINT8); + Guid->Data4[7] =3D ((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 sin= gle + call. + + @return Returns the maximum number of Entropy bits that can be returne= d + 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 entrop= y. + status: A Boolean value that is TRUE if the request has been satis= fied, + 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 =3D=3D 0) || + (EntropyBits > MAX_ENTROPY_BITS) || + (Buffer =3D=3D NULL)) + { + return RETURN_INVALID_PARAMETER; + } + + EntropyBytes =3D (EntropyBits + 7) >> 3; + if (EntropyBytes > BufferSize) { + return RETURN_BAD_BUFFER_SIZE; + } + + ZeroMem (Buffer, BufferSize); + ZeroMem (&Parameters, sizeof (Parameters)); + + Parameters.Arg0 =3D ARM_SMC_ID_TRNG_RND; + Parameters.Arg1 =3D EntropyBits; + ArmMonitorCall (&Parameters); + + Status =3D 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] =3D Parameters.Arg3; + EntropyData[1] =3D Parameters.Arg2; + EntropyData[2] =3D Parameters.Arg1; + + CopyMem (Buffer, EntropyData, EntropyBytes); + + // Mask off any unused top bytes, in accordance with specification. + BytesToClear =3D BufferSize - EntropyBytes; + if (BytesToClear !=3D 0) { + ZeroMem (&Buffer[EntropyBytes], BytesToClear); + } + + // Clear the unused MSB bits of the last byte. + LastValidBits =3D EntropyBits & 0x7; + if (LastValidBits !=3D 0) { + Buffer[EntropyBytes - 1] &=3D (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 =3D SMCCC_VERSION; + ArmMonitorCall (&Parameters); + Status =3D 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 =3D GetTrngVersion (&MajorRev, &MinorRev); + if (RETURN_ERROR (Status)) { + ASSERT_RETURN_ERROR (Status); + goto ErrorHandler; + } + + // Check that the required features are present. + Status =3D GetTrngFeatures (ARM_SMC_ID_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 =3D GetTrngFeatures (ARM_SMC_ID_TRNG_GET_UUID, NULL); + if (RETURN_ERROR (Status)) { + ASSERT_RETURN_ERROR (Status); + goto ErrorHandler; + } + + DEBUG_CODE_BEGIN (); + + Status =3D 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/Librar= y/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.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 1.29 + BASE_NAME =3D ArmFwTrngLib + FILE_GUID =3D 10DE97C9-28E4-4C9B-A53E-8D7D1B0DD4E0 + VERSION_STRING =3D 1.0 + MODULE_TYPE =3D BASE + LIBRARY_CLASS =3D TrngLib + CONSTRUCTOR =3D ArmFwTrngLibConstructor + +[Sources] + ArmFwTrngDefs.h + ArmFwTrngLib.c + +[Packages] + ArmPkg/ArmPkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + ArmMonitorLib + BaseLib + BaseMemoryLib --=20 2.25.1