--- /dev/null
+/** @file\r
+ OpenSSL_1_1_1b doesn't implement rand_pool_* functions for UEFI.\r
+ The file implement these functions.\r
+\r
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include "internal/rand_int.h"\r
+#include <openssl/aes.h>\r
+\r
+#include <Uefi.h>\r
+#include <Library/TimerLib.h>\r
+\r
+#include "rand_pool_noise.h"\r
+\r
+/**\r
+ Get some randomness from low-order bits of GetPerformanceCounter results.\r
+ And combine them to the 64-bit value\r
+\r
+ @param[out] Rand Buffer pointer to store the 64-bit random value.\r
+\r
+ @retval TRUE Random number generated successfully.\r
+ @retval FALSE Failed to generate.\r
+**/\r
+STATIC\r
+BOOLEAN\r
+EFIAPI\r
+GetRandNoise64FromPerformanceCounter(\r
+ OUT UINT64 *Rand\r
+ )\r
+{\r
+ UINT32 Index;\r
+ UINT32 *RandPtr;\r
+\r
+ if (NULL == Rand) {\r
+ return FALSE;\r
+ }\r
+\r
+ RandPtr = (UINT32 *) Rand;\r
+\r
+ for (Index = 0; Index < 2; Index ++) {\r
+ *RandPtr = (UINT32) (GetPerformanceCounter () & 0xFF);\r
+ MicroSecondDelay (10);\r
+ RandPtr++;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Calls RandomNumber64 to fill\r
+ a buffer of arbitrary size with random bytes.\r
+\r
+ @param[in] Length Size of the buffer, in bytes, to fill with.\r
+ @param[out] RandBuffer Pointer to the buffer to store the random result.\r
+\r
+ @retval EFI_SUCCESS Random bytes generation succeeded.\r
+ @retval EFI_NOT_READY Failed to request random bytes.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+EFIAPI\r
+RandGetBytes (\r
+ IN UINTN Length,\r
+ OUT UINT8 *RandBuffer\r
+ )\r
+{\r
+ BOOLEAN Ret;\r
+ UINT64 TempRand;\r
+\r
+ Ret = FALSE;\r
+\r
+ while (Length > 0) {\r
+ //\r
+ // Get random noise from platform.\r
+ // If it failed, fallback to PerformanceCounter\r
+ // If you really care about security, you must override\r
+ // GetRandomNoise64FromPlatform.\r
+ //\r
+ Ret = GetRandomNoise64 (&TempRand);\r
+ if (Ret == FALSE) {\r
+ Ret = GetRandNoise64FromPerformanceCounter (&TempRand);\r
+ }\r
+ if (!Ret) {\r
+ return Ret;\r
+ }\r
+ if (Length >= sizeof (TempRand)) {\r
+ *((UINT64*) RandBuffer) = TempRand;\r
+ RandBuffer += sizeof (UINT64);\r
+ Length -= sizeof (TempRand);\r
+ } else {\r
+ CopyMem (RandBuffer, &TempRand, Length);\r
+ Length = 0;\r
+ }\r
+ }\r
+\r
+ return Ret;\r
+}\r
+\r
+/**\r
+ Creates a 128bit random value that is fully forward and backward prediction resistant,\r
+ suitable for seeding a NIST SP800-90 Compliant.\r
+ This function takes multiple random numbers from PerformanceCounter to ensure reseeding\r
+ and performs AES-CBC-MAC over the data to compute the seed value.\r
+\r
+ @param[out] SeedBuffer Pointer to a 128bit buffer to store the random seed.\r
+\r
+ @retval TRUE Random seed generation succeeded.\r
+ @retval FALSE Failed to request random bytes.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+EFIAPI\r
+RandGetSeed128 (\r
+ OUT UINT8 *SeedBuffer\r
+ )\r
+{\r
+ BOOLEAN Ret;\r
+ UINT8 RandByte[16];\r
+ UINT8 Key[16];\r
+ UINT8 Ffv[16];\r
+ UINT8 Xored[16];\r
+ UINT32 Index;\r
+ UINT32 Index2;\r
+ AES_KEY AESKey;\r
+\r
+ //\r
+ // Chose an arbitary key and zero the feed_forward_value (FFV)\r
+ //\r
+ for (Index = 0; Index < 16; Index++) {\r
+ Key[Index] = (UINT8) Index;\r
+ Ffv[Index] = 0;\r
+ }\r
+\r
+ AES_set_encrypt_key (Key, 16 * 8, &AESKey);\r
+\r
+ //\r
+ // Perform CBC_MAC over 32 * 128 bit values, with 10us gaps between 128 bit value\r
+ // The 10us gaps will ensure multiple reseeds within the system time with a large\r
+ // design margin.\r
+ //\r
+ for (Index = 0; Index < 32; Index++) {\r
+ MicroSecondDelay (10);\r
+ Ret = RandGetBytes (16, RandByte);\r
+ if (!Ret) {\r
+ return Ret;\r
+ }\r
+\r
+ //\r
+ // Perform XOR operations on two 128-bit value.\r
+ //\r
+ for (Index2 = 0; Index2 < 16; Index2++) {\r
+ Xored[Index2] = RandByte[Index2] ^ Ffv[Index2];\r
+ }\r
+\r
+ AES_encrypt (Xored, Ffv, &AESKey);\r
+ }\r
+\r
+ for (Index = 0; Index < 16; Index++) {\r
+ SeedBuffer[Index] = Ffv[Index];\r
+ }\r
+\r
+ return Ret;\r
+}\r
+\r
+/**\r
+ Generate high-quality entropy source.\r
+\r
+ @param[in] Length Size of the buffer, in bytes, to fill with.\r
+ @param[out] Entropy Pointer to the buffer to store the entropy data.\r
+\r
+ @retval EFI_SUCCESS Entropy generation succeeded.\r
+ @retval EFI_NOT_READY Failed to request random data.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+EFIAPI\r
+RandGenerateEntropy (\r
+ IN UINTN Length,\r
+ OUT UINT8 *Entropy\r
+ )\r
+{\r
+ BOOLEAN Ret;\r
+ UINTN BlockCount;\r
+ UINT8 Seed[16];\r
+ UINT8 *Ptr;\r
+\r
+ BlockCount = Length / 16;\r
+ Ptr = (UINT8 *) Entropy;\r
+\r
+ //\r
+ // Generate high-quality seed for DRBG Entropy\r
+ //\r
+ while (BlockCount > 0) {\r
+ Ret = RandGetSeed128 (Seed);\r
+ if (!Ret) {\r
+ return Ret;\r
+ }\r
+ CopyMem (Ptr, Seed, 16);\r
+\r
+ BlockCount--;\r
+ Ptr = Ptr + 16;\r
+ }\r
+\r
+ //\r
+ // Populate the remained data as request.\r
+ //\r
+ Ret = RandGetSeed128 (Seed);\r
+ if (!Ret) {\r
+ return Ret;\r
+ }\r
+ CopyMem (Ptr, Seed, (Length % 16));\r
+\r
+ return Ret;\r
+}\r
+\r
+/*\r
+ * Add random bytes to the pool to acquire requested amount of entropy\r
+ *\r
+ * This function is platform specific and tries to acquire the requested\r
+ * amount of entropy by polling platform specific entropy sources.\r
+ *\r
+ * This is OpenSSL required interface.\r
+ */\r
+size_t rand_pool_acquire_entropy(RAND_POOL *pool)\r
+{\r
+ BOOLEAN Ret;\r
+ size_t bytes_needed;\r
+ unsigned char * buffer;\r
+\r
+ bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/);\r
+ if (bytes_needed > 0) {\r
+ buffer = rand_pool_add_begin(pool, bytes_needed);\r
+\r
+ if (buffer != NULL) {\r
+ Ret = RandGenerateEntropy(bytes_needed, buffer);\r
+ if (FALSE == Ret) {\r
+ rand_pool_add_end(pool, 0, 0);\r
+ } else {\r
+ rand_pool_add_end(pool, bytes_needed, 8 * bytes_needed);\r
+ }\r
+ }\r
+ }\r
+\r
+ return rand_pool_entropy_available(pool);\r
+}\r
+\r
+/*\r
+ * Implementation for UEFI\r
+ *\r
+ * This is OpenSSL required interface.\r
+ */\r
+int rand_pool_add_nonce_data(RAND_POOL *pool)\r
+{\r
+ struct {\r
+ UINT64 Rand;\r
+ UINT64 TimerValue;\r
+ } data = { 0 };\r
+\r
+ RandGetBytes(8, (UINT8 *)&(data.Rand));\r
+ data.TimerValue = GetPerformanceCounter();\r
+\r
+ return rand_pool_add(pool, (unsigned char*)&data, sizeof(data), 0);\r
+}\r
+\r
+/*\r
+ * Implementation for UEFI\r
+ *\r
+ * This is OpenSSL required interface.\r
+ */\r
+int rand_pool_add_additional_data(RAND_POOL *pool)\r
+{\r
+ struct {\r
+ UINT64 Rand;\r
+ UINT64 TimerValue;\r
+ } data = { 0 };\r
+\r
+ RandGetBytes(8, (UINT8 *)&(data.Rand));\r
+ data.TimerValue = GetPerformanceCounter();\r
+\r
+ return rand_pool_add(pool, (unsigned char*)&data, sizeof(data), 0);\r
+}\r
+\r
+/*\r
+ * Dummy Implememtation for UEFI\r
+ *\r
+ * This is OpenSSL required interface.\r
+ */\r
+int rand_pool_init(void)\r
+{\r
+ return 1;\r
+}\r
+\r
+/*\r
+ * Dummy Implememtation for UEFI\r
+ *\r
+ * This is OpenSSL required interface.\r
+ */\r
+void rand_pool_cleanup(void)\r
+{\r
+}\r
+\r
+/*\r
+ * Dummy Implememtation for UEFI\r
+ *\r
+ * This is OpenSSL required interface.\r
+ */\r
+void rand_pool_keep_random_devices_open(int keep)\r
+{\r
+}\r
+\r