TianoCore EDK2 master
Loading...
Searching...
No Matches
DxeRngLib.c
Go to the documentation of this file.
1
9#include <Uefi.h>
12#include <Library/DebugLib.h>
14#include <Library/RngLib.h>
15#include <Protocol/Rng.h>
16
17STATIC EFI_RNG_PROTOCOL *mRngProtocol;
18STATIC UINTN mFirstAlgo = MAX_UINTN;
19
20typedef struct {
23
25 CONST CHAR8 *Name;
26
28 BOOLEAN Available;
30
31//
32// These represent UEFI SPEC defined algorithms that should be supported by
33// the RNG protocol and are generally considered secure.
34//
35static GLOBAL_REMOVE_IF_UNREFERENCED SECURE_RNG_ALGO_ARRAY mSecureHashAlgorithms[] = {
36 #ifdef MDE_CPU_AARCH64
37 {
38 &gEfiRngAlgorithmArmRndr, // unspecified SP800-90A DRBG (through RNDR instr.)
39 "ARM-RNDR",
40 FALSE,
41 },
42 #endif
43 {
44 &gEfiRngAlgorithmSp80090Ctr256Guid, // SP800-90A DRBG CTR using AES-256
45 "DRBG-CTR",
46 FALSE,
47 },
48 {
49 &gEfiRngAlgorithmSp80090Hmac256Guid, // SP800-90A DRBG HMAC using SHA-256
50 "DRBG-HMAC",
51 FALSE,
52 },
53 {
54 &gEfiRngAlgorithmSp80090Hash256Guid, // SP800-90A DRBG Hash using SHA-256
55 "DRBG-Hash",
56 FALSE,
57 },
58 {
59 &gEfiRngAlgorithmRaw, // Raw data from NRBG (or TRNG)
60 "TRNG",
61 FALSE,
62 },
63};
64
76EFIAPI
78 IN EFI_HANDLE ImageHandle,
79 IN EFI_SYSTEM_TABLE *SystemTable
80 )
81{
82 EFI_STATUS Status;
83 UINTN RngArraySize;
84 UINTN RngArrayCnt;
85 UINT32 Index;
86 UINT32 Index1;
87 EFI_RNG_ALGORITHM *RngArray;
88
89 Status = gBS->LocateProtocol (&gEfiRngProtocolGuid, NULL, (VOID **)&mRngProtocol);
90 if (EFI_ERROR (Status) || (mRngProtocol == NULL)) {
91 DEBUG ((DEBUG_ERROR, "%a: Could not locate RNG protocol, Status = %r\n", __func__, Status));
92 return Status;
93 }
94
95 RngArraySize = 0;
96
97 Status = mRngProtocol->GetInfo (mRngProtocol, &RngArraySize, NULL);
98 if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {
99 return Status;
100 } else if (RngArraySize == 0) {
101 return EFI_NOT_FOUND;
102 }
103
104 RngArrayCnt = RngArraySize / sizeof (*RngArray);
105
106 RngArray = AllocateZeroPool (RngArraySize);
107 if (RngArray == NULL) {
108 return EFI_OUT_OF_RESOURCES;
109 }
110
111 Status = mRngProtocol->GetInfo (mRngProtocol, &RngArraySize, RngArray);
112 if (EFI_ERROR (Status)) {
113 goto ExitHandler;
114 }
115
116 for (Index = 0; Index < RngArrayCnt; Index++) {
117 for (Index1 = 0; Index1 < ARRAY_SIZE (mSecureHashAlgorithms); Index1++) {
118 if (CompareGuid (&RngArray[Index], mSecureHashAlgorithms[Index1].Guid)) {
119 mSecureHashAlgorithms[Index1].Available = TRUE;
120 if (mFirstAlgo == MAX_UINTN) {
121 mFirstAlgo = Index1;
122 }
123
124 break;
125 }
126 }
127 }
128
129ExitHandler:
130 FreePool (RngArray);
131 return Status;
132}
133
147STATIC
150 OUT UINT8 *Buffer,
151 IN UINTN BufferSize
152 )
153{
154 EFI_STATUS Status;
155 UINTN Index;
157
158 if (Buffer == NULL) {
159 DEBUG ((DEBUG_ERROR, "%a: Buffer == NULL.\n", __func__));
160 return EFI_INVALID_PARAMETER;
161 }
162
163 if (mRngProtocol == NULL) {
164 return EFI_NOT_FOUND;
165 }
166
167 // Try the first available algorithm.
168 if (mFirstAlgo != MAX_UINTN) {
169 Algo = &mSecureHashAlgorithms[mFirstAlgo];
170 Status = mRngProtocol->GetRNG (mRngProtocol, Algo->Guid, BufferSize, Buffer);
171 DEBUG ((
172 DEBUG_INFO,
173 "%a: GetRNG algorithm %a - Status = %r\n",
174 __func__,
175 Algo->Name,
176 Status
177 ));
178 if (!EFI_ERROR (Status)) {
179 return Status;
180 }
181
182 Index = mFirstAlgo + 1;
183 } else {
184 Index = 0;
185 }
186
187 // Iterate over other available algorithms.
188 for ( ; Index < ARRAY_SIZE (mSecureHashAlgorithms); Index++) {
189 Algo = &mSecureHashAlgorithms[Index];
190 if (!Algo->Available) {
191 continue;
192 }
193
194 Status = mRngProtocol->GetRNG (mRngProtocol, Algo->Guid, BufferSize, Buffer);
195 DEBUG ((
196 DEBUG_INFO,
197 "%a: GetRNG algorithm %a - Status = %r\n",
198 __func__,
199 Algo->Name,
200 Status
201 ));
202 if (!EFI_ERROR (Status)) {
203 return Status;
204 }
205 }
206
207 if (!PcdGetBool (PcdEnforceSecureRngAlgorithms)) {
208 // If all the other methods have failed, use the default method from the RngProtocol
209 Status = mRngProtocol->GetRNG (mRngProtocol, NULL, BufferSize, Buffer);
210 DEBUG ((DEBUG_INFO, "%a: GetRNG algorithm default - Status = %r\n", __func__, Status));
211 if (!EFI_ERROR (Status)) {
212 return Status;
213 }
214 }
215
216 // If we get to this point, we have failed
217 DEBUG ((DEBUG_ERROR, "%a: GetRNG() failed, Status = %r\n", __func__, Status));
218
219 return Status;
220}// GenerateRandomNumberViaNist800Algorithm()
221
233BOOLEAN
234EFIAPI
236 OUT UINT16 *Rand
237 )
238{
239 EFI_STATUS Status;
240
241 if (Rand == NULL) {
242 return FALSE;
243 }
244
245 Status = GenerateRandomNumberViaNist800Algorithm ((UINT8 *)Rand, sizeof (UINT16));
246 if (EFI_ERROR (Status)) {
247 return FALSE;
248 }
249
250 return TRUE;
251}
252
264BOOLEAN
265EFIAPI
267 OUT UINT32 *Rand
268 )
269{
270 EFI_STATUS Status;
271
272 if (Rand == NULL) {
273 return FALSE;
274 }
275
276 Status = GenerateRandomNumberViaNist800Algorithm ((UINT8 *)Rand, sizeof (UINT32));
277 if (EFI_ERROR (Status)) {
278 return FALSE;
279 }
280
281 return TRUE;
282}
283
295BOOLEAN
296EFIAPI
298 OUT UINT64 *Rand
299 )
300{
301 EFI_STATUS Status;
302
303 if (Rand == NULL) {
304 return FALSE;
305 }
306
307 Status = GenerateRandomNumberViaNist800Algorithm ((UINT8 *)Rand, sizeof (UINT64));
308 if (EFI_ERROR (Status)) {
309 return FALSE;
310 }
311
312 return TRUE;
313}
314
326BOOLEAN
327EFIAPI
329 OUT UINT64 *Rand
330 )
331{
332 EFI_STATUS Status;
333
334 if (Rand == NULL) {
335 return FALSE;
336 }
337
338 Status = GenerateRandomNumberViaNist800Algorithm ((UINT8 *)Rand, 2 * sizeof (UINT64));
339 if (EFI_ERROR (Status)) {
340 return FALSE;
341 }
342
343 return TRUE;
344}
345
357EFIAPI
359 GUID *RngGuid
360 )
361{
362 /* It is not possible to know beforehand which Rng algorithm will
363 * be used by this library.
364 * This API is mainly used by RngDxe. RngDxe relies on the RngLib.
365 * The RngLib|DxeRngLib.inf implementation locates and uses an installed
366 * EFI_RNG_PROTOCOL.
367 * It is thus not possible to have both RngDxe and RngLib|DxeRngLib.inf.
368 * and it is ok not to support this API.
369 */
370 return EFI_UNSUPPORTED;
371}
UINT64 UINTN
BOOLEAN EFIAPI CompareGuid(IN CONST GUID *Guid1, IN CONST GUID *Guid2)
Definition: MemLibGuid.c:73
BOOLEAN EFIAPI GetRandomNumber16(OUT UINT16 *Rand)
Definition: DxeRngLib.c:235
EFI_STATUS EFIAPI GetRngGuid(GUID *RngGuid)
Definition: DxeRngLib.c:358
BOOLEAN EFIAPI GetRandomNumber32(OUT UINT32 *Rand)
Definition: DxeRngLib.c:266
BOOLEAN EFIAPI GetRandomNumber128(OUT UINT64 *Rand)
Definition: DxeRngLib.c:328
EFI_STATUS EFIAPI DxeRngLibConstructor(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
Definition: DxeRngLib.c:77
STATIC EFI_STATUS GenerateRandomNumberViaNist800Algorithm(OUT UINT8 *Buffer, IN UINTN BufferSize)
Definition: DxeRngLib.c:149
BOOLEAN EFIAPI GetRandomNumber64(OUT UINT64 *Rand)
Definition: DxeRngLib.c:297
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define STATIC
Definition: Base.h:264
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define ARRAY_SIZE(Array)
Definition: Base.h:1393
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define GLOBAL_REMOVE_IF_UNREFERENCED
Definition: Base.h:48
#define DEBUG(Expression)
Definition: DebugLib.h:434
#define PcdGetBool(TokenName)
Definition: PcdLib.h:401
UINTN Rand(VOID)
Definition: Support.c:39
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
EFI_BOOT_SERVICES * gBS
Definition: Base.h:213
BOOLEAN Available
The algorithm is available for use.
Definition: DxeRngLib.c:28
CONST CHAR8 * Name
Algorithm name.
Definition: DxeRngLib.c:25
EFI_GUID * Guid
Guid of the secure algorithm.
Definition: DxeRngLib.c:22