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

Leif Lindholm quic_llindhol at quicinc.com
Wed Oct 5 11:43:46 UTC 2022


On Mon, Oct 03, 2022 at 09:34:53 +0200, PierreGondois wrote:
> 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>

Acked-by: Leif Lindholm <quic_llindhol at 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/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