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