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.web11.15707.1656530381004631752 for ; Wed, 29 Jun 2022 12:19:41 -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 ED36B14BF; Wed, 29 Jun 2022 12:19:40 -0700 (PDT) Received: from pierre123.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id C52B93F792; Wed, 29 Jun 2022 12:19:38 -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 RESEND v1 7/9] MdePkg/DrbgLib: Add Drbg mechanism functions and module Date: Wed, 29 Jun 2022 21:18:44 +0200 Message-Id: <20220629191848.2619317-8-Pierre.Gondois@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220629191848.2619317-1-Pierre.Gondois@arm.com> References: <20220629191848.2619317-1-Pierre.Gondois@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Pierre Gondois BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3D3971 >>From the NIST Special Publication 800-90A, the implementation of a Drbg can be split into: 1. DRBG Mechanism Functions (s9 of the spec), describing the operations generic to all the mechanisms. 2. DRBG Algorithm Specifications (s10 of the spec), describing the operations specific to each mechanisms (CTR, HMAC, ...) This patch implements 1., i.e. the operations generic to all the mechanisms. Functions implemented here are also the DrbgLib interface. The .inf file associated to the module is also added here. Signed-off-by: Pierre Gondois Signed-off-by: Sami Mujawar --- MdePkg/Library/DrbgLib/DrbgLib.c | 628 +++++++++++++++++++++++ MdePkg/Library/DrbgLib/DrbgLib.inf | 39 ++ MdePkg/Library/DrbgLib/DrbgLibInternal.h | 310 +++++++++++ MdePkg/MdePkg.dsc | 1 + 4 files changed, 978 insertions(+) create mode 100644 MdePkg/Library/DrbgLib/DrbgLib.c create mode 100644 MdePkg/Library/DrbgLib/DrbgLib.inf create mode 100644 MdePkg/Library/DrbgLib/DrbgLibInternal.h diff --git a/MdePkg/Library/DrbgLib/DrbgLib.c b/MdePkg/Library/DrbgLib/Dr= bgLib.c new file mode 100644 index 000000000000..bfad8fc670be --- /dev/null +++ b/MdePkg/Library/DrbgLib/DrbgLib.c @@ -0,0 +1,628 @@ +/** @file + Drbg library. + Cf. [1] s9 DRBG Mechanism Functions + + Copyright (c) 2022, Arm Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - [1] 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) + - [2] 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) + - [3] (Second Draft) NIST Special Publication 800-90C, Recommendation = for + Random Bit Generator (RBG) Constructions. + (https://csrc.nist.gov/publications/detail/sp/800-90c/draft) + - [4] NIST Special Publication 800-57 Part 1 Revision 5, May 2020, + Recommendation for Key Management:Part 1 - General. + (https://csrc.nist.gov/publications/detail/sp/800-57-part-1/rev-= 5/final) + - [5] Unified Extensible Firmware Interface (UEFI) Specification, + Version 2.8 Errata B, May 2020 + (https://www.uefi.org/specifications) + + @par Glossary: + - TRNG - True Random Number Generator + - Sec - Security + - DRBG - Deterministic Random Bits Generator + - CTR - Counter +**/ + +#include +#include +#include +#include + +#include "Common.h" +#include "GetEntropyInput.h" + +/** Check the internal state of the Drbg handle. + + @param [in] DrbgHandle The Drbg handle. + + @retval TRUE The Drbg handle has a valid internal state. + @retval FALSE Otherwise. +**/ +STATIC +BOOLEAN +CheckInternalState ( + IN DRBG_HANDLE DrbgHandle + ) +{ + if ((DrbgHandle =3D=3D NULL) || + EFI_ERROR (DrbgHandle->DrbgCheckInternalState (DrbgHandle))) + { + ASSERT (DrbgHandle !=3D NULL); + ASSERT_EFI_ERROR (DrbgHandle->DrbgCheckInternalState (DrbgHandle)); + return FALSE; + } + + return TRUE; +} + +/** Reseed a DRBG instance. + + Implementation of Reseed_function. + Cf. [1] s9.2 'Reseeding a DRBG Instantiation' + + @param [in] PredResRequest Indicates whether prediction resistance + is to be provided during the request. + Might not be supported by all Drbgs. + @param [in] AddInput An optional additional input. + Might not be supported by all Drbgs. + @param [in] AddInputLen Additional input length (in bits). + Might not be supported by all Drbgs. + @param [in, out] DrbgHandle The Drbg handle. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Out of resources. +**/ +EFI_STATUS +EFIAPI +DrbgReseedFn ( + IN BOOLEAN PredResRequest, + IN CONST CHAR8 *AddInput, + IN UINTN AddInputLen, + IN OUT VOID *Handle + ) +{ + EFI_STATUS Status; + DRBG_HANDLE DrbgHandle; + BIT_STREAM *AddInputStream; + BIT_STREAM *EntropyBitsStream; + + DrbgHandle =3D (DRBG_HANDLE)Handle; + + // 1. Using state_handle, obtain the current internal state. + // If state_handle indicates an invalid or unused internal state, + // return (ERROR_FLAG). + if (((AddInput =3D=3D NULL) ^ (AddInputLen =3D=3D 0)) || + !CheckInternalState (DrbgHandle)) + { + ASSERT (!((AddInput =3D=3D NULL) ^ (AddInputLen =3D=3D 0))); + ASSERT (CheckInternalState (DrbgHandle)); + return EFI_INVALID_PARAMETER; + } + + AddInputStream =3D NULL; + EntropyBitsStream =3D NULL; + + // 2. If prediction_resistance_request is set, and prediction_resistan= ce_flag + // is not set, then return (ERROR_FLAG). + if (PredResRequest && !DrbgHandle->IntState.PredResFlag) { + ASSERT (!(PredResRequest && !DrbgHandle->IntState.PredResFlag)); + return EFI_INVALID_PARAMETER; + } + + // 3. If the length of the additional_input > max_additional_input_len= gth, + // return (ERROR_FLAG). + if (AddInputLen > DrbgHandle->DrbgVal.MaxAddInputLen) { + ASSERT (AddInputLen <=3D DrbgHandle->DrbgVal.MaxAddInputLen); + return EFI_INVALID_PARAMETER; + } + + // 4. (status, entropy_input) =3D Get_entropy_input (security_strength= , + // min_length, max_length, prediction_resistance_request). + // 5. If (status !=3D SUCCESS), return (status). + // + // Note: in this implementation, there is no difference between + // ERROR_FLAG and CATASTROPHIC_ERROR_FLAG. + Status =3D DrbgHandle->DrbgGetEntropyInput ( + DrbgHandle, + DrbgHandle->DrbgVal.MinLen, + &EntropyBitsStream + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Create a BitStream for AddInput, even for a NULL AddInput. AddInput= is + // used during instantiation but doesn't persist in the Drbg handle. + Status =3D BitStreamInit ( + (UINT8 *)AddInput, + AddInputLen, + &AddInputStream + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + // 6. new_working_state =3D Reseed_algorithm (working_state, entropy_i= nput, + // additional_input). + // 7. Replace the working_state in the internal state for the DRBG + // instantiation (e.g., as indicated by state_handle) with the values = of + // new_working_state obtained in step 6. + Status =3D DrbgHandle->DrbgReseedAlgo ( + EntropyBitsStream, + AddInputStream, + DrbgHandle + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + // Fall trough + } + +ExitHandler: + if (AddInputStream !=3D NULL) { + BitStreamFree (&AddInputStream); + } + + if (EntropyBitsStream !=3D NULL) { + BitStreamFree (&EntropyBitsStream); + } + + // 8. Return (SUCCESS). + return Status; +} + +/** Create a Drbg instance. + + Implementation of Instantiate_function. + Cf. [1] s9.1 Instantiating a DRBG + + @param [in] DrbgMechanism DRBG mechanism chosen. + @param [in] DrbgEntropySrc Entropy source chosen. + @param [in] ReqSecStrength Requested security strength (in bits). + The security strenght granted can be dif= ferent. + @param [in] PredRes Prediction resistance flag. + If relevant, instantiate a DRBG that sup= ports + prediction resistance. + Might not be supported by all Drbgs. + @param [in] PersStr Personnalization string. + Might not be supported by all Drbgs. + @param [in] PersStrLen Personnalization string length (in bits)= . + Might not be supported by all Drbgs. + @param [out] HandlePtr Pointer containting the created Drbg handle. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Out of resources. +**/ +EFI_STATUS +EFIAPI +DrbgInstantiateFn ( + IN DRBG_MECHANISM DrbgMechanism, + IN DRBG_ENTROPY_SRC DrbgEntropySrc, + IN UINTN ReqSecStrength, + IN BOOLEAN PredRes, + IN CONST CHAR8 *PersStr, + IN UINTN PersStrLen, + OUT VOID **HandlePtr + ) +{ + EFI_STATUS Status; + BIT_STREAM *EntropyBitsStream; + BIT_STREAM *PersStrBitStream; + DRBG_HANDLE DrbgHandle; + + if ((ReqSecStrength =3D=3D 0) || + ((PersStr =3D=3D NULL) ^ (PersStrLen =3D=3D 0)) || + (HandlePtr =3D=3D NULL)) + { + ASSERT (ReqSecStrength !=3D 0); + ASSERT (!((PersStr =3D=3D NULL) ^ (PersStrLen =3D=3D 0))); + ASSERT (HandlePtr !=3D NULL); + return EFI_INVALID_PARAMETER; + } + + // Allocate a Drbg. + DrbgHandle =3D AllocateZeroPool (sizeof (DRBG_INFO)); + if (DrbgHandle =3D=3D NULL) { + ASSERT (DrbgHandle !=3D NULL); + return EFI_OUT_OF_RESOURCES; + } + + // Init the handle according to the mechanism. + switch (DrbgMechanism) { + case DrbgMechansimCtr: + Status =3D CtrInitHandle (DrbgHandle); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + break; + + default: + Status =3D EFI_INVALID_PARAMETER; + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + // Init the handle according to entropy. + switch (DrbgEntropySrc) { + case DrbgEntropyNoCondFn: + DrbgHandle->DrbgGetEntropyInput =3D GetEntropyInputNoCondFn; + break; + + default: + Status =3D EFI_INVALID_PARAMETER; + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + EntropyBitsStream =3D NULL; + PersStrBitStream =3D NULL; + + // 1. If requested_instantiation_security_strength > + // highest_supported_security_strength, + // then return (ERROR_FLAG, Invalid). + if (ReqSecStrength > DrbgHandle->DrbgVal.HighestSuppSecStrength) { + ASSERT (ReqSecStrength <=3D DrbgHandle->DrbgVal.HighestSuppSecStreng= th); + goto ExitHandler; + } + + // 2. If prediction_resistance_flag is set, and prediction resistance + // is not supported, then return (ERROR_FLAG, Invalid). + if (!DrbgHandle->PredResSupported && PredRes) { + ASSERT (!(!DrbgHandle->PredResSupported && PredRes)); + goto ExitHandler; + } + + if (PersStr !=3D NULL) { + // 3. If the length of the personalization_string > + // max_personalization_string_length, + // return (ERROR_FLAG, Invalid). + if (PersStrLen > DrbgHandle->DrbgVal.MaxPersStrLen) { + ASSERT (PersStrLen <=3D DrbgHandle->DrbgVal.MaxPersStrLen); + goto ExitHandler; + } + } + + // 4. Set security_strength to the lowest security strength greater th= an or + // equal to requested_instantiation_security_strength from the set + // {112, 128, 192, 256}. + // + // Note: [5], Section 37.5 Random Number Generator Protocol: + // 'When a Deterministic Random Bit Generator (DRBG) is used on the + // output of a (raw) entropy source, its security level must be at + // least 256 bits.' + // So set the security strength to 256. + // + // Note2: Set it here so CTR_DRBG_Instantiate_algorithm has access to = it. + DrbgHandle->IntState.SecStrength =3D SecStrength256bits; + DEBUG (( + DEBUG_INFO, + "Requested security strength =3D %d bits. " \ + "Setting security strength for DRBG to %d bits.\n", + ReqSecStrength, + SecStrength256bits + )); + + // Create a BitStream for PersStr, even for a NULL PersStr. PersStr is + // used during instantiation but doesn't persist in the Drbg handle. + Status =3D BitStreamInit ( + (UINT8 *)PersStr, + PersStrLen, + &PersStrBitStream + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + // 5. Null step. + // 6. (status, entropy_input) =3D Get_entropy_input (security_strength= , + // min_length, max_length, prediction_resistance_request). + // + // Note: in this implementation, there is no difference between + // ERROR_FLAG and CATASTROPHIC_ERROR_FLAG. + // + // 7. If (status !=3D SUCCESS), return (status, Invalid). + Status =3D DrbgHandle->DrbgGetEntropyInput ( + DrbgHandle, + DrbgHandle->DrbgVal.MinLen, + &EntropyBitsStream + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + // 8. Obtain a nonce. + Status =3D DrbgHandle->DrbgGetNonce (DrbgHandle, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + // 9. initial_working_state =3D Instantiate_algorithm (entropy_input, = nonce, + // personalization_string, security_strength). + Status =3D DrbgHandle->DrbgInstantiateAlgo ( + EntropyBitsStream, + PersStrBitStream, + DrbgHandle + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + // 10. Get a state_handle for a currently empty internal state. If an = empty + // internal state cannot be found, return (ERROR_FLAG, Invalid). + // 11. Set the internal state for the new instantiation (e.g., as indi= cated + // by state_handle) to the initial values for the internal state (i.e.= , set + // the working_state to the values returned as initial_working_state i= n + // step 9) and any other values required for the working_state (see + // Section 10), and set the administrative information to the appropri= ate + // values (e.g., the values of security_strength and the + // prediction_resistance_flag). + DrbgHandle->IntState.PredResFlag =3D PredRes; + // DrbgInstantiateAlgo already sets ReseedCounter + +ExitHandler: + if (EntropyBitsStream !=3D NULL) { + BitStreamFree (&EntropyBitsStream); + } + + if (PersStrBitStream !=3D NULL) { + BitStreamFree (&PersStrBitStream); + } + + if (EFI_ERROR (Status)) { + FreePool (DrbgHandle); + DrbgHandle =3D NULL; + } + + // 12. Return (SUCCESS, state_handle). + *HandlePtr =3D (VOID **)DrbgHandle; + return Status; +} + +/** Generate a random number. + + Implementation of Generate_function. + Cf. [1] s9.3.1 The Generate Function + + @param [in] ReqSecStrength Requested security strength (in bits). + If the DrbgHandle cannot satisfy the req= uest, + an error is returned. + @param [in] PredResReq Request prediction resistance. + If the DrbgHandle cannot satisfy the req= uest, + an error is returned. + @param [in] AddInput Additional input. + Might not be supported by all Drbgs. + @param [in] AddInputLen Additional input length (in bits). + Might not be supported by all Drbgs. + @param [in] ReqNbBits Number of random bits requested. + @param [in, out] OutBuffer If success, contains the random bits. + The buffer must be at least ReqNbBits bi= ts + long. + @param [in, out] DrbgHandle The Drbg handle. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Out of resources. +**/ +EFI_STATUS +EFIAPI +DrbgGenerateFn ( + IN UINTN ReqSecStrength, + IN BOOLEAN PredResReq, + IN CONST CHAR8 *AddInput, + IN UINTN AddInputLen, + IN UINTN ReqNbBits, + IN OUT UINT8 *OutBuffer, + IN OUT VOID *Handle + ) +{ + EFI_STATUS Status; + DRBG_HANDLE DrbgHandle; + BOOLEAN ReseedReq; + BIT_STREAM *AddInputStream; + BIT_STREAM *RandomBitsStream; + + DrbgHandle =3D (DRBG_HANDLE)Handle; + + // 1. Using state_handle, obtain the current internal state for the + // instantiation. If state_handle indicates an invalid or unused inter= nal + // state, then return (ERROR_FLAG, Null). + if ((ReqSecStrength =3D=3D 0) || + ((AddInput !=3D NULL) ^ (AddInputLen !=3D 0)) || + (ReqNbBits =3D=3D 0) || + (OutBuffer =3D=3D NULL) || + !CheckInternalState (DrbgHandle)) + { + ASSERT (ReqSecStrength !=3D 0); + ASSERT (!((AddInput !=3D NULL) ^ (AddInputLen !=3D 0))); + ASSERT (ReqNbBits !=3D 0); + ASSERT (OutBuffer !=3D NULL); + ASSERT (CheckInternalState (DrbgHandle)); + return EFI_INVALID_PARAMETER; + } + + AddInputStream =3D NULL; + RandomBitsStream =3D NULL; + + // 2. If requested_number_of_bits > max_number_of_bits_per_request, + // then return (ERROR_FLAG, Null). + if (ReqNbBits > DrbgHandle->DrbgVal.MaxNbBitsPerRequest) { + ASSERT (ReqNbBits <=3D DrbgHandle->DrbgVal.MaxNbBitsPerRequest); + return EFI_INVALID_PARAMETER; + } + + // 3. If requested_security_strength > the security_strength indicated + // in the internal state, then return (ERROR_FLAG, Null). + if (ReqSecStrength > DrbgHandle->IntState.SecStrength) { + ASSERT (ReqSecStrength <=3D DrbgHandle->IntState.SecStrength); + return EFI_INVALID_PARAMETER; + } + + // 4. If the length of the additional_input > max_additional_input_len= gth, + // then return (ERROR_FLAG, Null). + if (AddInputLen > DrbgHandle->DrbgVal.MaxAddInputLen) { + ASSERT (AddInputLen <=3D DrbgHandle->DrbgVal.MaxAddInputLen); + return EFI_INVALID_PARAMETER; + } + + // 5. If prediction_resistance_request is set, and prediction_resistan= ce_flag + // is not set, then return (ERROR_FLAG, Null). + if (PredResReq && !DrbgHandle->IntState.PredResFlag) { + ASSERT (!(PredResReq && !DrbgHandle->IntState.PredResFlag)); + return EFI_INVALID_PARAMETER; + } + + // 6. Clear the reseed_required_flag. + ReseedReq =3D FALSE; + + // 7. If reseed_required_flag is set, or if prediction_resistance_requ= est is + // set, then +Step7: + if (ReseedReq || PredResReq) { + // 7.1 status =3D Reseed_function (state_handle, + // prediction_resistance_request, additional_input)= . + // 7.2 If (status !=3D SUCCESS), then return (status, Null). + // 7.3 Using state_handle, obtain the new internal state. + // + // Note: in this implementation, there is no difference between + // ERROR_FLAG and CATASTROPHIC_ERROR_FLAG. + Status =3D DrbgReseedFn ( + PredResReq, + AddInput, + AddInputLen, + DrbgHandle + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + // 7.4 additional_input =3D the Null string. + AddInput =3D NULL; + AddInputLen =3D 0; + + // 7.5 Clear the reseed_required_flag. + ReseedReq =3D FALSE; + } + + // Create a BitStream for AddInput, even for a NULL AddInput. AddInput= is + // used during instantiation but doesn't persist in the Drbg handle. + Status =3D BitStreamInit ( + (UINT8 *)AddInput, + AddInputLen, + &AddInputStream + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + // 8. (status, pseudorandom_bits, new_working_state) =3D + // Generate_algorithm (working_state, requested_number_of_bits, + // additional_input). + Status =3D DrbgHandle->DrbgGenerateAlgo ( + AddInputStream, + ReqNbBits, + &RandomBitsStream, + DrbgHandle + ); + if (EFI_ERROR (Status) && (Status !=3D EFI_NOT_READY)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + // Free AddInputStream now that it has been used. + if (AddInputStream !=3D NULL) { + BitStreamFree (&AddInputStream); + } + + // 9. If status indicates that a reseed is required before the request= ed + // bits can be generated, then + if (Status =3D=3D EFI_NOT_READY) { + if (DrbgHandle->ReseedSupported) { + // 9.1 Set the reseed_required_flag. + ReseedReq =3D TRUE; + + // 9.2 If the prediction_resistance_flag is set, then set the + // prediction_resistance request indication. + if (DrbgHandle->IntState.PredResFlag) { + PredResReq =3D TRUE; + } + + // 9.3 Go to step 7. + goto Step7; + } else { + // Implementation notes: + // If a reseed capability is not supported, or a reseed is not des= ired, + // then generate process steps 6 and 7 are removed; generate proce= ss + // step 9 is replaced by: + // 9. If status indicates that a reseed is required before the req= uested + // bits can be generated, then + // 9.1 status =3D Uninstantiate_function (state_handle). + // + // No need to check the returned status. + DrbgUninstantiateFn (DrbgHandle); + + // 9.2 Return an indication that the DRBG instantiation can no lon= ger be used. + goto ExitHandler; + } + } + + // The Drbg succeeded, copy the random bits. + Status =3D BitStreamToBuffer (RandomBitsStream, OutBuffer); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + // Fall through. + } + + // 10. Replace the old working_state in the internal state of the DRBG + // instantiation (e.g., as indicated by state_handle) with the values = of + // new_working_state. + // 11. Return (SUCCESS, pseudorandom_bits). +ExitHandler: + if (AddInputStream !=3D NULL) { + BitStreamFree (&AddInputStream); + } + + if (RandomBitsStream !=3D NULL) { + BitStreamFree (&RandomBitsStream); + } + + return Status; +} + +/** Remove a DRBG instance. + + Implementation of Uninstantiate_function. + Cf. [1] s9.4 Removing a DRBG Instantiation + + @param [in, out] DrbgHandle The Drbg handle. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. +**/ +EFI_STATUS +EFIAPI +DrbgUninstantiateFn ( + IN OUT VOID *Handle + ) +{ + DRBG_HANDLE DrbgHandle; + + DrbgHandle =3D (DRBG_HANDLE)Handle; + return DrbgHandle->DrbgUninstantiateFn (DrbgHandle); +} diff --git a/MdePkg/Library/DrbgLib/DrbgLib.inf b/MdePkg/Library/DrbgLib/= DrbgLib.inf new file mode 100644 index 000000000000..34272aa88d85 --- /dev/null +++ b/MdePkg/Library/DrbgLib/DrbgLib.inf @@ -0,0 +1,39 @@ +## @file +# Drbg library +# +# Copyright (c) 2022, Arm Limited. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x0001001B + BASE_NAME =3D DrbgLib + FILE_GUID =3D 454B071B-FD44-4055-B689-E06B6FE5D3D7 + VERSION_STRING =3D 1.0 + MODULE_TYPE =3D DXE_DRIVER + LIBRARY_CLASS =3D DrbgLib + +# +# VALID_ARCHITECTURES =3D AARCH64 ARM +# + +[Sources] + BitStream.c + BitStream.h + Common.c + Common.h + CtrDrbg.c + CtrDrbg.h + DrbgLib.c + DrbgLibInternal.h + GetEntropyInput.c + GetEntropyInput.h + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + AesLib + BaseLib + TrngLib diff --git a/MdePkg/Library/DrbgLib/DrbgLibInternal.h b/MdePkg/Library/Dr= bgLib/DrbgLibInternal.h new file mode 100644 index 000000000000..6cf681951431 --- /dev/null +++ b/MdePkg/Library/DrbgLib/DrbgLibInternal.h @@ -0,0 +1,310 @@ +/** @file + Arm DRBG library internal definitions. + Cf. [1] s9 DRBG Mechanism Functions + + Copyright (c) 2022, Arm Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + + - [1] 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) + - [2] 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) + - [3] (Second Draft) NIST Special Publication 800-90C, Recommendation = for + Random Bit Generator (RBG) Constructions. + (https://csrc.nist.gov/publications/detail/sp/800-90c/draft) + - [4] NIST Special Publication 800-57 Part 1 Revision 5, May 2020, + Recommendation forKey Management:Part 1 - General. + (https://csrc.nist.gov/publications/detail/sp/800-57-part-1/rev-= 5/final) + - [5] Unified Extensible Firmware Interface (UEFI) Specification, + Version 2.8 Errata B, May 2020 + (https://www.uefi.org/specifications) + + @par Glossary: + - TRNG - True Random Number Generator + - Sec - Security + - DRBG - Deterministic Random Bits Generator + - CTR - Counter +**/ + +#ifndef ARM_DRBG_LIB_INTERNAL_H_ +#define ARM_DRBG_LIB_INTERNAL_H_ + +// Forward declarations of DRBG_INFO. +typedef struct DrbgInfo DRBG_INFO; +typedef DRBG_INFO *DRBG_HANDLE; + +#include +#include +#include "BitStream.h" + +/** Security strengths for block cipher algorithms. + + Cf [2] 5.6.1.1, Table 2: Comparable security strengths of symmetric = block + cipher and asymmetric-key algorithms. + + [2]: 'Although 3TDEA is listed as providing 112 bits of security str= ength, + its use has been deprecated (see SP 800-131A)' +*/ +typedef enum { + SecStrengthMin =3D 128, ///< Min Security strength o= f 128 bits. + SecStrength128bits =3D SecStrengthMin, ///< Security strength of 12= 8 bits. + SecStrength196bits =3D 196, ///< Security strength of 19= 6 bits. + SecStrength256bits =3D 256, ///< Security strength of 25= 6 bits. + SecStrengthMax =3D SecStrength256bits ///< Maximum Security streng= th. +} SECURITY_STRENGTH; + +/** Get a nonce. + + @param [in, out] DrbgHandle The Drbg handle. + @param [out] NonceStream Stream containing the Nonce. + + @retval EFI_SUCCESS Success. +**/ +typedef EFI_STATUS EFIAPI (*DRBG_GET_NONCE) ( + IN OUT DRBG_HANDLE DrbgHandle, + OUT BIT_STREAM *NonceStream + ); + +/** Check the internal state of the Drbg handle. + + @param [in] DrbgHandle The Drbg handle. + + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_SUCCESS Success. +**/ +typedef EFI_STATUS EFIAPI (*DRBG_CHECK_INTERNAL_STATE) ( + IN DRBG_HANDLE DrbgHandle + ); + +/** GetEntropyInput implementation (no conditionning function). + + Cf. [3] 10.3.3 Get_entropy_input Constructions for Accessing Entropy S= ources + + @param [in] DrbgHandle The Drbg hanble. + @param [in] MinEntropy Minimum entropy. + @param [out] EntropyBitsStream Stream containing the generated entrop= y. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Out of resources. +**/ +typedef EFI_STATUS EFIAPI (*DRBG_GET_ENTROPY_INTPUT) ( + IN DRBG_HANDLE DrbgHandle, + IN UINTN MinEntropy, + OUT BIT_STREAM **EntropyBitsStream + ); + +/** Update algorithm. + + CTR_DRBG_Update implementation. + + Cf. [1] s10.2.1.2 The Update Function (CTR_DRBG_Update) + + @param [in] ProvidedData The data to be used. This must be exac= tly + seedlen bits in length. + @param [in, out] DrbgHandle The Drbg handle. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Out of resources. +**/ +typedef EFI_STATUS EFIAPI (*DRBG_UPDATE) ( + IN BIT_STREAM *ProvidedData, + IN OUT DRBG_HANDLE DrbgHandle + ); + +/** Reseed algorithm + + @param [in] EntropyInput The string of bits obtained from the + randomness source. + @param [in] AddInput The additional input string received + from the consuming application. Note + that the length of the additional_inpu= t + string may be zero. + @param [in, out] DrbgHandle The Drbg handle. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Out of resources. +**/ +typedef EFI_STATUS EFIAPI (*DRBG_RESEED) ( + IN BIT_STREAM *EntropyInput, + IN BIT_STREAM *AddInput, + IN OUT DRBG_HANDLE DrbgHandle + ); + +/** Instantiate algorithm. + + CTR_DRBG_Instantiate_algorithm implementation. + + Cf. [1] s10.2.1.3.1 Instantiation When a Derivation Function is Not Us= ed + + @param [in] EntropyInput The string of bits obtained from the + randomness source. + @param [in] PersStrBitStream The personalization string received fr= om the + consuming application. Note that the l= ength + of the personalization_string may be z= ero. + Note: PersStrBitStream must be initial= ized, + even with a NULL BitStream. + @param [out] DrbgHandle The Drbg handle. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Out of resources. +**/ +typedef EFI_STATUS EFIAPI (*DRBG_INSTANTIATE) ( + IN BIT_STREAM *EntropyInput, + IN BIT_STREAM *PersStrBitStream, + OUT DRBG_HANDLE DrbgHandle + ); + +/** Generate algorithm. + + @param [in] AddInput The additional input string receiv= ed from + the consuming application. Note th= at the + length of the additional_input str= ing + may be zero. + @param [in] RequestedNbBits The number of pseudorandom bits to= be + returned to the generate function. + @param [out] RndBitStream BitStream containing the random bi= ts. + @param [in, out] DrbgHandle The Drbg handle. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_NOT_READY A reseed is required before the reques= ted + pseudorandom bits can be generated. +**/ +typedef EFI_STATUS EFIAPI (*DRBG_GENERATE_ALGORITHM) ( + IN BIT_STREAM *AddInput, + IN UINTN RequestedNbBits, + OUT BIT_STREAM **RndBitStream, + IN OUT DRBG_HANDLE DrbgHandle + ); + +/** Uninstantiate a DRBG instance. + + @param [in, out] DrbgHandle The Drbg handle. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. +**/ +typedef EFI_STATUS EFIAPI (*DRBG_UNINSTANTIATE_FUNCTION) ( + IN OUT DRBG_HANDLE DrbgHandle + ); + +/** Drbg algo specific value definitions. +*/ +typedef VOID *DRBG_ALGO_VALUE_DEFINITIONS; + +/** Drbg algo internal state values. +*/ +typedef VOID *DRBG_ALGO_INTERNAL_STATE; + +/** Drbg values definitions. + + Values are specific to a Drbg mechanism. + Cf. [1]: + Table 2: Definitions for Hash-Based DRBG Mechanisms + Table 3: Definitions for the CTR_DRBG +*/ +typedef struct { + /// Supported security strengths. + // Not applicable. + /// Highest supported security strength. + SECURITY_STRENGTH HighestSuppSecStrength; + /// Minimum entropy input length. + UINTN MinLen; + /// Maximum entropy input length. + UINTN MaxLen; + /// Maximum personalization string length. + UINTN MaxPersStrLen; + /// Maximum additional_input length. + UINTN MaxAddInputLen; + /// Maximum number of bits per request. + UINTN MaxNbBitsPerRequest; + + /// Drbg algo specific value definitions. + DRBG_ALGO_VALUE_DEFINITIONS DrbgAlgoVal; +} DRBG_VALUE_DEFINITIONS; + +/** Internal state. + + For a Drbg mechanism, values are specific to a Drbg instance. +*/ +typedef struct { + // Administrative information. + /// Security strength + SECURITY_STRENGTH SecStrength; + /// Prediction resistance flag + BOOLEAN PredResFlag; + + /// Drbg algo specific internal state values. + DRBG_ALGO_INTERNAL_STATE DrbgAlgoIntState; +} DRBG_INTERNAL_STATE; + +/** Drbg info structure. + + This structure is a Drbg instance. It contains information specific to= the + Drbg mechanism chosen (e.g. the block size for Ctr mechanism) and inst= ance + specific information (i.e. the internal state of the instance). +*/ +struct DrbgInfo { + /// Drbg mechanism used. + DRBG_MECHANISM DrbgMechanism; + /// GUID of the algorithm used. + EFI_RNG_ALGORITHM Algo; + + /// Values specifics to the Drbg mechanism used. + DRBG_VALUE_DEFINITIONS DrbgVal; + + /// Internal state of the Drbg instance. + DRBG_INTERNAL_STATE IntState; + + /// Prediction resistance is supported for this Drbg instance. + BOOLEAN PredResSupported; + /// Reseeding is supported for this Drbg instance. + BOOLEAN ReseedSupported; + + /// Callback to get a nonce. + DRBG_GET_NONCE DrbgGetNonce; + /// Callback to check the internal state. + DRBG_CHECK_INTERNAL_STATE DrbgCheckInternalState; + /// Callback to get some entropy. + DRBG_GET_ENTROPY_INTPUT DrbgGetEntropyInput; + + /// Callback to update the instance + /// (according to the mechanism used). + DRBG_UPDATE DrbgUpdate; + /// Callback to reseed the instance + /// (according to the mechanism used). + DRBG_RESEED DrbgReseedAlgo; + /// Callback to instantiate the Drbg instance + /// (according to the mechanism used). + DRBG_INSTANTIATE DrbgInstantiateAlgo; + /// Callback to generate random bits the instance + /// (according to the mechanism used). + DRBG_GENERATE_ALGORITHM DrbgGenerateAlgo; + /// Callback to uninstantiate the Drbg instance + /// (according to the mechanism used). + DRBG_UNINSTANTIATE_FUNCTION DrbgUninstantiateFn; +}; + +/** Drbg mechanism specific instantiation steps. + + @param [in, out] DrbgHandle The Drbg handle. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. +**/ +EFI_STATUS +EFIAPI +CtrInitHandle ( + IN OUT DRBG_HANDLE DrbgHandle + ); + +#endif // ARM_DRBG_LIB_INTERNAL_H_ diff --git a/MdePkg/MdePkg.dsc b/MdePkg/MdePkg.dsc index 4820cecd0db8..5926a179d810 100644 --- a/MdePkg/MdePkg.dsc +++ b/MdePkg/MdePkg.dsc @@ -70,6 +70,7 @@ [Components] MdePkg/Library/BaseTrngLibNull/BaseTrngLibNull.inf MdePkg/Library/AesLibNull/AesLibNull.inf MdePkg/Library/DrbgLibNull/DrbgLibNull.inf + MdePkg/Library/DrbgLib/DrbgLib.inf =20 MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf --=20 2.25.1