[PATCH v3 08/22] ArmPkg/TrngLib: Add Arm Firmware TRNG library


PierreGondois
 

From: Sami Mujawar <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.

Signed-off-by: Sami Mujawar <sami.mujawar@...>
---
ArmPkg/ArmPkg.dsc | 1 +
ArmPkg/Library/ArmFwTrngLib/ArmFwTrngDefs.h | 50 +++
ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.c | 403 +++++++++++++++++++
ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.inf | 29 ++
4 files changed, 483 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 e33b40f2c215..02d1caa3ab40 100644
--- a/ArmPkg/ArmPkg.dsc
+++ b/ArmPkg/ArmPkg.dsc
@@ -138,6 +138,7 @@ [Components.common]
ArmPkg/Library/ArmSvcLib/ArmSvcLib.inf
ArmPkg/Library/ArmMonitorLib/ArmMonitorLib.inf
ArmPkg/Library/OpteeLib/OpteeLib.inf
+ ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.inf
=20
ArmPkg/Filesystem/SemihostFs/SemihostFs.inf
=20
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..5cff23de0250
--- /dev/null
+++ b/ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.c
@@ -0,0 +1,403 @@
+/** @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] 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, Recommen=
dation
+ for Random Number Generation Using Deterministic Random Bit Gene=
rators.
+ (https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/fina=
l)
+ - [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/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 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 FID_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 FID_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 FID_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 [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 entrop=
y.
+ status: A Boolean value that is TRUE if the request has been satis=
fied,
+ and is FALSE otherwise.
+
+ Note: In this implementation this function returns a status code inste=
ad
+ of a boolean value.
+ This is also compatible with the definition of Get_Entropy, see =
[4]
+ Section 7.4 Entropy Source Calls.
+ (status, entropy_bitstring) =3D Get_Entropy (
+ requested_entropy,
+ max_length
+ )
+
+ @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 FID_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 (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 =3D GetTrngFeatures (FID_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..baeb00d832fd
--- /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 =3D 0x0001001B
+ 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