@@ -22,6 +22,89 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
2222
2323#define RANDOM_SEED_BUFFER_SIZE 64 // We'll seed with 64 bytes of random so that OAEP can work its best.
2424
25+ //
26+ // These represent UEFI SPEC defined algorithms that should be supported by
27+ // the RNG protocol and are generally considered secure for DFCI purposes.
28+ //
29+ static EFI_GUID * CONST mSecureRngAlgorithms [] = {
30+ & gEfiRngAlgorithmSp80090Ctr256Guid , // SP800-90A DRBG CTR using AES-256
31+ & gEfiRngAlgorithmSp80090Hmac256Guid , // SP800-90A DRBG HMAC using SHA-256
32+ & gEfiRngAlgorithmSp80090Hash256Guid , // SP800-90A DRBG Hash using SHA-256
33+ & gEfiRngAlgorithmArmRndr , // unspecified SP800-90B DRBG via ARM RNDR register
34+ };
35+
36+ #define SECURE_RNG_ALGORITHMS_SIZE (ARRAY_SIZE (mSecureRngAlgorithms))
37+
38+ /**
39+ Generate a random output of a given length using an algorithm considered secure.
40+
41+ @param[out] Output The buffer to store the generated random data.
42+ @param[in] OutputLength The length of the output buffer.
43+
44+ @retval EFI_SUCCESS The random data was generated successfully.
45+ @retval EFI_INVALID_PARAMETER The output buffer is NULL or the output length is zero.
46+ @retval EFI_NOT_FOUND RNG protocol not found or a secure algorithm is not supported.
47+ @retval Others An error occurred while generating random data.
48+ **/
49+ EFI_STATUS
50+ EFIAPI
51+ GetRandomValue (
52+ OUT VOID * Output ,
53+ IN UINTN OutputLength
54+ )
55+ {
56+ EFI_RNG_PROTOCOL * RngProtocol ;
57+ EFI_STATUS Status ;
58+ UINTN AlgorithmIndex ;
59+
60+ if ((Output == NULL ) || (OutputLength == 0 )) {
61+ return EFI_INVALID_PARAMETER ;
62+ }
63+
64+ Status = gBS -> LocateProtocol (& gEfiRngProtocolGuid , NULL , (VOID * * )& RngProtocol );
65+ if (EFI_ERROR (Status )) {
66+ DEBUG ((DEBUG_ERROR , "%a: Failed to locate EFI_RNG_PROTOCOL: %r\n" , __func__ , Status ));
67+ ASSERT_EFI_ERROR (Status );
68+ return Status ;
69+ }
70+
71+ for (AlgorithmIndex = 0 ; AlgorithmIndex < SECURE_RNG_ALGORITHMS_SIZE ; AlgorithmIndex ++ ) {
72+ Status = RngProtocol -> GetRNG (RngProtocol , mSecureRngAlgorithms [AlgorithmIndex ], OutputLength , (UINT8 * )Output );
73+ if (!EFI_ERROR (Status )) {
74+ //
75+ // The secure algorithm is supported on this platform
76+ //
77+ return EFI_SUCCESS ;
78+ } else if (Status == EFI_UNSUPPORTED ) {
79+ //
80+ // The secure algorithm is not supported on this platform
81+ //
82+ DEBUG ((DEBUG_VERBOSE , "%a: Failed to generate random data using secure algorithm %d: %r\n" , __func__ , AlgorithmIndex , Status ));
83+
84+ //
85+ // Try the next secure algorithm
86+ //
87+ continue ;
88+ } else {
89+ //
90+ // Some other error occurred
91+ //
92+ DEBUG ((DEBUG_ERROR , "%a: Failed to generate random data using secure algorithm %d: %r\n" , __func__ , AlgorithmIndex , Status ));
93+ ASSERT_EFI_ERROR (Status );
94+ return Status ;
95+ }
96+ }
97+
98+ //
99+ // If we get here, we failed to generate random data using any secure algorithm
100+ // Platform owner should ensure that at least one secure algorithm is supported
101+ //
102+ DEBUG ((DEBUG_ERROR , "%a: Failed to generate random data, no supported secure algorithm found\n" , __func__ ));
103+ ASSERT_EFI_ERROR (Status );
104+
105+ return EFI_NOT_FOUND ;
106+ }
107+
25108/**
26109 This function will attempt to allocate and populate a buffer
27110 with a DFCI recovery challenge structure. If unsuccessful,
@@ -45,7 +128,6 @@ GetRecoveryChallenge (
45128{
46129 EFI_STATUS Status ;
47130 DFCI_RECOVERY_CHALLENGE * NewChallenge ;
48- EFI_RNG_PROTOCOL * RngProtocol ;
49131 CHAR8 * Element ;
50132 UINTN ElementSize ;
51133
@@ -63,14 +145,6 @@ GetRecoveryChallenge (
63145 * Challenge = NULL ;
64146 NewChallenge = NULL ;
65147
66- //
67- // Locate the RNG Protocol. This will be needed for the nonce.
68- Status = gBS -> LocateProtocol (& gEfiRngProtocolGuid , NULL , (VOID * * )& RngProtocol );
69- if (EFI_ERROR (Status )) {
70- DEBUG ((DEBUG_ERROR , "%a: LocateProtocol(RNG) = %r\n" , __FUNCTION__ , Status ));
71- return EFI_NOT_FOUND ;
72- }
73-
74148 //
75149 // From now on, don't proceed on errors.
76150 //
@@ -94,43 +168,13 @@ GetRecoveryChallenge (
94168
95169 //
96170 // Grab a timestamp...
97- if (!EFI_ERROR (Status )) {
98- Status = gRT -> GetTime (& NewChallenge -> Timestamp , NULL );
99- DEBUG ((DEBUG_VERBOSE , "%a: GetTime() = %r\n" , __FUNCTION__ , Status ));
100- }
171+ Status = gRT -> GetTime (& NewChallenge -> Timestamp , NULL );
172+ DEBUG ((DEBUG_VERBOSE , "%a: GetTime() = %r\n" , __FUNCTION__ , Status ));
101173
102174 //
103175 // Generate the random nonce...
104176 if (!EFI_ERROR (Status )) {
105- Status = RngProtocol -> GetRNG (
106- RngProtocol ,
107- & gEfiRngAlgorithmSp80090Ctr256Guid ,
108- DFCI_RECOVERY_NONCE_SIZE ,
109- & NewChallenge -> Nonce .Bytes [0 ]
110- );
111- DEBUG ((DEBUG_VERBOSE , "%a: GetRNG(Ctr256) = %r\n" , __FUNCTION__ , Status ));
112- //
113- // If Ctr256 failed, let's try Hmac256
114- if (EFI_ERROR (Status )) {
115- Status = RngProtocol -> GetRNG (
116- RngProtocol ,
117- & gEfiRngAlgorithmSp80090Hmac256Guid ,
118- DFCI_RECOVERY_NONCE_SIZE ,
119- & NewChallenge -> Nonce .Bytes [0 ]
120- );
121- DEBUG ((DEBUG_VERBOSE , "%a: GetRNG(Hmac256) = %r\n" , __FUNCTION__ , Status ));
122- //
123- // Finally, try Hash256
124- if (EFI_ERROR (Status )) {
125- Status = RngProtocol -> GetRNG (
126- RngProtocol ,
127- & gEfiRngAlgorithmSp80090Hash256Guid ,
128- DFCI_RECOVERY_NONCE_SIZE ,
129- & NewChallenge -> Nonce .Bytes [0 ]
130- );
131- DEBUG ((DEBUG_VERBOSE , "%a: GetRNG(Hash256) = %r\n" , __FUNCTION__ , Status ));
132- }
133- }
177+ Status = GetRandomValue (& NewChallenge -> Nonce .Bytes [0 ], DFCI_RECOVERY_NONCE_SIZE );
134178 }
135179
136180 //
@@ -204,7 +248,8 @@ GetRecoveryChallenge (
204248
205249 @retval EFI_SUCCESS Challenge was successfully encrypted and can be found in buffer.
206250 @retval EFI_INVALID_PARAMETER Nuff said.
207- @retval EFI_NOT_FOUND Could not locate the RNG protocol.
251+ @retval EFI_NOT_FOUND Could not locate the RNG protocol or a secure RNG algorithm
252+ supported by the platform.
208253 @retval EFI_ABORTED Call to Pkcs1v2Encrypt() failed.
209254 @retval Others Error returned from LocateProtocol or GetRNG.
210255
@@ -219,9 +264,8 @@ EncryptRecoveryChallenge (
219264 OUT UINTN * EncryptedDataSize
220265 )
221266{
222- EFI_STATUS Status ;
223- EFI_RNG_PROTOCOL * RngProtocol ;
224- UINT8 ExtraSeed [RANDOM_SEED_BUFFER_SIZE ];
267+ EFI_STATUS Status ;
268+ UINT8 ExtraSeed [RANDOM_SEED_BUFFER_SIZE ];
225269
226270 DEBUG ((DEBUG_INFO , "%a()\n" , __FUNCTION__ ));
227271
@@ -242,40 +286,7 @@ EncryptRecoveryChallenge (
242286 // NOTE: This *could* be done with a direct call to RandomSeed() rather than
243287 // passing it into the Pkcs1v2Encrypt() function. There are merits to
244288 // each implementation.
245- Status = gBS -> LocateProtocol (& gEfiRngProtocolGuid , NULL , (VOID * * )& RngProtocol );
246- DEBUG ((DEBUG_VERBOSE , "%a: LocateProtocol(RNG) = %r\n" , __FUNCTION__ , Status ));
247- // Assuming we found the protocol, let's grab a seed.
248- if (!EFI_ERROR (Status )) {
249- Status = RngProtocol -> GetRNG (
250- RngProtocol ,
251- & gEfiRngAlgorithmSp80090Ctr256Guid ,
252- RANDOM_SEED_BUFFER_SIZE ,
253- & ExtraSeed [0 ]
254- );
255- DEBUG ((DEBUG_VERBOSE , "%a: GetRNG(Ctr256) = %r\n" , __FUNCTION__ , Status ));
256- //
257- // If Ctr256 failed, let's try Hmac256
258- if (EFI_ERROR (Status )) {
259- Status = RngProtocol -> GetRNG (
260- RngProtocol ,
261- & gEfiRngAlgorithmSp80090Hmac256Guid ,
262- RANDOM_SEED_BUFFER_SIZE ,
263- & ExtraSeed [0 ]
264- );
265- DEBUG ((DEBUG_VERBOSE , "%a: GetRNG(Hmac256) = %r\n" , __FUNCTION__ , Status ));
266- //
267- // Finally, try Hash256
268- if (EFI_ERROR (Status )) {
269- Status = RngProtocol -> GetRNG (
270- RngProtocol ,
271- & gEfiRngAlgorithmSp80090Hash256Guid ,
272- RANDOM_SEED_BUFFER_SIZE ,
273- & ExtraSeed [0 ]
274- );
275- DEBUG ((DEBUG_VERBOSE , "%a: GetRNG(Hash256) = %r\n" , __FUNCTION__ , Status ));
276- }
277- }
278- }
289+ Status = GetRandomValue (& ExtraSeed [0 ], RANDOM_SEED_BUFFER_SIZE );
279290
280291 //
281292 // Now, we should be able to encrypt the data and be done with it.
0 commit comments