Skip to content

Commit 4261f78

Browse files
authored
DfciPkg/DfciRecoveryLib: Add support for Arm RNDR RNG algorithm (#297)
## Description 1. Consolidate logic for determining whether the RNG protocol is available and a secure algorithm is supported by the platform in DfciRecoveryLib.c. 2. Update the list of algorithms that are considered secure for the purposes of DFCI usage to include `gEfiRngAlgorithmArmRndr` for a DRBG via the Arm RNDR register. Platforms producing `gEfiRngAlgorithmArmRndr` should ensure it supports NIST SP800-90B compliance as described in https://developer.arm.com/documentation/100685/0000/Overview-of-Arm-True-Random-Number-Generator--TRNG-. - [x] Impacts functionality? - [x] Impacts security? - [ ] Breaking change? - [ ] Includes tests? - [ ] Includes documentation? ## How This Was Tested - CI - Platform test in progress ## Integration Instructions - `gEfiRngAlgorithmArmRndr` will be used if present in the RNG algorithm. Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
1 parent 8e652e5 commit 4261f78

File tree

2 files changed

+92
-80
lines changed

2 files changed

+92
-80
lines changed

DfciPkg/Library/DfciRecoveryLib/DfciRecoveryLib.c

Lines changed: 91 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -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.

DfciPkg/Library/DfciRecoveryLib/DfciRecoveryLib.inf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
gEfiRngAlgorithmSp80090Ctr256Guid
4848
gEfiRngAlgorithmSp80090Hmac256Guid
4949
gEfiRngAlgorithmSp80090Hash256Guid
50+
gEfiRngAlgorithmArmRndr
5051

5152

5253
## Required for drivers.

0 commit comments

Comments
 (0)