]> git.proxmox.com Git - mirror_edk2.git/blob - CryptoPkg/Library/OpensslLib/rand_pool.c
CryptoPkg/OpensslLib: Add functions for upgrading OpenSSL1_1_1b
[mirror_edk2.git] / CryptoPkg / Library / OpensslLib / rand_pool.c
1 /** @file
2 OpenSSL_1_1_1b doesn't implement rand_pool_* functions for UEFI.
3 The file implement these functions.
4
5 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "internal/rand_int.h"
11 #include <openssl/aes.h>
12
13 #include <Uefi.h>
14 #include <Library/TimerLib.h>
15
16 #include "rand_pool_noise.h"
17
18 /**
19 Get some randomness from low-order bits of GetPerformanceCounter results.
20 And combine them to the 64-bit value
21
22 @param[out] Rand Buffer pointer to store the 64-bit random value.
23
24 @retval TRUE Random number generated successfully.
25 @retval FALSE Failed to generate.
26 **/
27 STATIC
28 BOOLEAN
29 EFIAPI
30 GetRandNoise64FromPerformanceCounter(
31 OUT UINT64 *Rand
32 )
33 {
34 UINT32 Index;
35 UINT32 *RandPtr;
36
37 if (NULL == Rand) {
38 return FALSE;
39 }
40
41 RandPtr = (UINT32 *) Rand;
42
43 for (Index = 0; Index < 2; Index ++) {
44 *RandPtr = (UINT32) (GetPerformanceCounter () & 0xFF);
45 MicroSecondDelay (10);
46 RandPtr++;
47 }
48
49 return TRUE;
50 }
51
52 /**
53 Calls RandomNumber64 to fill
54 a buffer of arbitrary size with random bytes.
55
56 @param[in] Length Size of the buffer, in bytes, to fill with.
57 @param[out] RandBuffer Pointer to the buffer to store the random result.
58
59 @retval EFI_SUCCESS Random bytes generation succeeded.
60 @retval EFI_NOT_READY Failed to request random bytes.
61
62 **/
63 STATIC
64 BOOLEAN
65 EFIAPI
66 RandGetBytes (
67 IN UINTN Length,
68 OUT UINT8 *RandBuffer
69 )
70 {
71 BOOLEAN Ret;
72 UINT64 TempRand;
73
74 Ret = FALSE;
75
76 while (Length > 0) {
77 //
78 // Get random noise from platform.
79 // If it failed, fallback to PerformanceCounter
80 // If you really care about security, you must override
81 // GetRandomNoise64FromPlatform.
82 //
83 Ret = GetRandomNoise64 (&TempRand);
84 if (Ret == FALSE) {
85 Ret = GetRandNoise64FromPerformanceCounter (&TempRand);
86 }
87 if (!Ret) {
88 return Ret;
89 }
90 if (Length >= sizeof (TempRand)) {
91 *((UINT64*) RandBuffer) = TempRand;
92 RandBuffer += sizeof (UINT64);
93 Length -= sizeof (TempRand);
94 } else {
95 CopyMem (RandBuffer, &TempRand, Length);
96 Length = 0;
97 }
98 }
99
100 return Ret;
101 }
102
103 /**
104 Creates a 128bit random value that is fully forward and backward prediction resistant,
105 suitable for seeding a NIST SP800-90 Compliant.
106 This function takes multiple random numbers from PerformanceCounter to ensure reseeding
107 and performs AES-CBC-MAC over the data to compute the seed value.
108
109 @param[out] SeedBuffer Pointer to a 128bit buffer to store the random seed.
110
111 @retval TRUE Random seed generation succeeded.
112 @retval FALSE Failed to request random bytes.
113
114 **/
115 STATIC
116 BOOLEAN
117 EFIAPI
118 RandGetSeed128 (
119 OUT UINT8 *SeedBuffer
120 )
121 {
122 BOOLEAN Ret;
123 UINT8 RandByte[16];
124 UINT8 Key[16];
125 UINT8 Ffv[16];
126 UINT8 Xored[16];
127 UINT32 Index;
128 UINT32 Index2;
129 AES_KEY AESKey;
130
131 //
132 // Chose an arbitary key and zero the feed_forward_value (FFV)
133 //
134 for (Index = 0; Index < 16; Index++) {
135 Key[Index] = (UINT8) Index;
136 Ffv[Index] = 0;
137 }
138
139 AES_set_encrypt_key (Key, 16 * 8, &AESKey);
140
141 //
142 // Perform CBC_MAC over 32 * 128 bit values, with 10us gaps between 128 bit value
143 // The 10us gaps will ensure multiple reseeds within the system time with a large
144 // design margin.
145 //
146 for (Index = 0; Index < 32; Index++) {
147 MicroSecondDelay (10);
148 Ret = RandGetBytes (16, RandByte);
149 if (!Ret) {
150 return Ret;
151 }
152
153 //
154 // Perform XOR operations on two 128-bit value.
155 //
156 for (Index2 = 0; Index2 < 16; Index2++) {
157 Xored[Index2] = RandByte[Index2] ^ Ffv[Index2];
158 }
159
160 AES_encrypt (Xored, Ffv, &AESKey);
161 }
162
163 for (Index = 0; Index < 16; Index++) {
164 SeedBuffer[Index] = Ffv[Index];
165 }
166
167 return Ret;
168 }
169
170 /**
171 Generate high-quality entropy source.
172
173 @param[in] Length Size of the buffer, in bytes, to fill with.
174 @param[out] Entropy Pointer to the buffer to store the entropy data.
175
176 @retval EFI_SUCCESS Entropy generation succeeded.
177 @retval EFI_NOT_READY Failed to request random data.
178
179 **/
180 STATIC
181 BOOLEAN
182 EFIAPI
183 RandGenerateEntropy (
184 IN UINTN Length,
185 OUT UINT8 *Entropy
186 )
187 {
188 BOOLEAN Ret;
189 UINTN BlockCount;
190 UINT8 Seed[16];
191 UINT8 *Ptr;
192
193 BlockCount = Length / 16;
194 Ptr = (UINT8 *) Entropy;
195
196 //
197 // Generate high-quality seed for DRBG Entropy
198 //
199 while (BlockCount > 0) {
200 Ret = RandGetSeed128 (Seed);
201 if (!Ret) {
202 return Ret;
203 }
204 CopyMem (Ptr, Seed, 16);
205
206 BlockCount--;
207 Ptr = Ptr + 16;
208 }
209
210 //
211 // Populate the remained data as request.
212 //
213 Ret = RandGetSeed128 (Seed);
214 if (!Ret) {
215 return Ret;
216 }
217 CopyMem (Ptr, Seed, (Length % 16));
218
219 return Ret;
220 }
221
222 /*
223 * Add random bytes to the pool to acquire requested amount of entropy
224 *
225 * This function is platform specific and tries to acquire the requested
226 * amount of entropy by polling platform specific entropy sources.
227 *
228 * This is OpenSSL required interface.
229 */
230 size_t rand_pool_acquire_entropy(RAND_POOL *pool)
231 {
232 BOOLEAN Ret;
233 size_t bytes_needed;
234 unsigned char * buffer;
235
236 bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/);
237 if (bytes_needed > 0) {
238 buffer = rand_pool_add_begin(pool, bytes_needed);
239
240 if (buffer != NULL) {
241 Ret = RandGenerateEntropy(bytes_needed, buffer);
242 if (FALSE == Ret) {
243 rand_pool_add_end(pool, 0, 0);
244 } else {
245 rand_pool_add_end(pool, bytes_needed, 8 * bytes_needed);
246 }
247 }
248 }
249
250 return rand_pool_entropy_available(pool);
251 }
252
253 /*
254 * Implementation for UEFI
255 *
256 * This is OpenSSL required interface.
257 */
258 int rand_pool_add_nonce_data(RAND_POOL *pool)
259 {
260 struct {
261 UINT64 Rand;
262 UINT64 TimerValue;
263 } data = { 0 };
264
265 RandGetBytes(8, (UINT8 *)&(data.Rand));
266 data.TimerValue = GetPerformanceCounter();
267
268 return rand_pool_add(pool, (unsigned char*)&data, sizeof(data), 0);
269 }
270
271 /*
272 * Implementation for UEFI
273 *
274 * This is OpenSSL required interface.
275 */
276 int rand_pool_add_additional_data(RAND_POOL *pool)
277 {
278 struct {
279 UINT64 Rand;
280 UINT64 TimerValue;
281 } data = { 0 };
282
283 RandGetBytes(8, (UINT8 *)&(data.Rand));
284 data.TimerValue = GetPerformanceCounter();
285
286 return rand_pool_add(pool, (unsigned char*)&data, sizeof(data), 0);
287 }
288
289 /*
290 * Dummy Implememtation for UEFI
291 *
292 * This is OpenSSL required interface.
293 */
294 int rand_pool_init(void)
295 {
296 return 1;
297 }
298
299 /*
300 * Dummy Implememtation for UEFI
301 *
302 * This is OpenSSL required interface.
303 */
304 void rand_pool_cleanup(void)
305 {
306 }
307
308 /*
309 * Dummy Implememtation for UEFI
310 *
311 * This is OpenSSL required interface.
312 */
313 void rand_pool_keep_random_devices_open(int keep)
314 {
315 }
316