[edk2-devel] [PATCH v7 09/19] ArmPkg/TrngLib: Add Arm Firmware TRNG library

PierreGondois pierre.gondois at arm.com
Mon Oct 3 07:34:53 UTC 2022


From: Sami Mujawar <sami.mujawar at 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.gondois at arm.com>
---
 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 (#94644): https://edk2.groups.io/g/devel/message/94644
Mute This Topic: https://groups.io/mt/94085853/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-




More information about the edk2-devel-archive mailing list