diff --git a/src/tpm2/Entropy.c b/src/tpm2/Entropy.c index 45908368..ece0327f 100644 --- a/src/tpm2/Entropy.c +++ b/src/tpm2/Entropy.c @@ -3,7 +3,7 @@ /* */ /* Written by Ken Goldman */ /* IBM Thomas J. Watson Research Center */ -/* $Id: Entropy.c 1091 2017-10-31 20:31:59Z kgoldman $ */ +/* $Id: Entropy.c 1259 2018-07-10 19:11:09Z kgoldman $ */ /* */ /* Licenses and Notices */ /* */ @@ -55,7 +55,7 @@ /* arising in any way out of use or reliance upon this specification or any */ /* information herein. */ /* */ -/* (c) Copyright IBM Corp. and others, 2016, 2017 */ +/* (c) Copyright IBM Corp. and others, 2016 - 2018 */ /* */ /********************************************************************************/ @@ -69,6 +69,14 @@ #include "PlatformData.h" #include "Platform_fp.h" + +#include +#ifdef _MSC_VER +#include +#else +#include +#endif + /* C.4.2. Local values */ /* This is the last 32-bits of hardware entropy produced. We have to check to see that two consecutive 32-bit values are not the same because (according to FIPS 140-2, annex C */ @@ -78,11 +86,34 @@ compared with the previously generated block. The test shall fail if any two compared n-bit blocks are equal." */ extern uint32_t lastEntropy; -extern int firstValue; -/* C.4.3. _plat__GetEntropy() */ + +/* C.4.3.1. rand64() */ +/* Local function to get a 32-bit random number */ +static uint32_t +rand32( + void + ) +{ + uint32_t rndNum = rand(); +#if RAND_MAX < UINT16_MAX + // If the maximum value of the random number is a 15-bit number, then shift it up + // 15 bits, get 15 more bits, shift that up 2 and then XOR in another value to get + // a full 32 bits. + rndNum = (rndNum << 15) ^ rand(); + rndNum = (rndNum << 2) ^ rand(); +#elif RAND_MAX == UINT16_MAX + // If the maximum size is 16-bits, shift it and add another 16 bits + rndNum = (rndNum << 16) ^ rand(); +#elif RAND_MAX < UINT32_MAX + // If 31 bits, then shift 1 and include another random value to get the extra bit + rndNum = (rndNum << 1) ^ rand(); +#endif + return rndNum; +} + +/* C.4.3.2 _plat__GetEntropy() */ /* This function is used to get available hardware entropy. In a hardware implementation of this - function, there would be no call to the system to get entropy. If the caller does not ask for any - entropy, then this is a startup indication and firstValue should be reset. */ + function, there would be no call to the system to get entropy. */ /* Return Values Meaning */ /* < 0 hardware failure of the entropy generator, this is sticky */ /* >= 0 the returned amount of entropy (bytes) */ @@ -93,27 +124,60 @@ _plat__GetEntropy( ) { uint32_t rndNum; - int OK = 1; + int32_t ret; + // + // libtpms added: + if (amount > 0 && RAND_bytes(entropy, amount) == 1) + return amount; + // fall back to 'original' method + if(amount == 0) { - firstValue = 1; - return 0; + // Seed the platform entropy source if the entropy source is software. There is + // no reason to put a guard macro (#if or #ifdef) around this code because this + // code would not be here if someone was changing it for a system with actual + // hardware. + // + // NOTE 1: The following command does not provide proper cryptographic entropy. + // Its primary purpose to make sure that different instances of the simulator, + // possibly started by a script on the same machine, are seeded differently. + // But vendors of the actual TPMs need to ensure availability of proper entropy + // using their platform specific means. + // + // NOTE 2: In debug builds by default the reference implementation will seed + // its RNG deterministically (without using any platform provided randomness). + // See the USE_DEBUG_RNG macro and DRBG_GetEntropy() function. +#ifdef _MSC_VER + srand((unsigned)_plat__RealTime() ^ _getpid()); +#else + srand((unsigned)_plat__RealTime() ^ getpid()); +#endif + lastEntropy = rand32(); + ret = 0; } - // Only provide entropy 32 bits at a time to test the ability - // of the caller to deal with partial results. - /* rndNum = rand(); kgold rand() is not random */ - RAND_bytes((unsigned char *)&rndNum, sizeof(uint32_t)); /* kgold */ - - if(firstValue) - firstValue = 0; else - OK = (rndNum != lastEntropy); - if(OK) { - lastEntropy = rndNum; - if(amount > sizeof(rndNum)) - amount = sizeof(rndNum); - memcpy(entropy, &rndNum, amount); + rndNum = rand32(); + if(rndNum == lastEntropy) + { + ret = -1; + } + else + { + lastEntropy = rndNum; + // Each process will have its random number generator initialized according + // to the process id and the initialization time. This is not a lot of + // entropy so, to add a bit more, XOR the current time value into the + // returned entropy value. + // NOTE: the reason for including the time here rather than have it in + // in the value assigned to lastEntropy is that rand() could be broken and + // using the time would in the lastEntropy value would hide this. + rndNum ^= (uint32_t)_plat__RealTime(); + // Only provide entropy 32 bits at a time to test the ability + // of the caller to deal with partial results. + ret = MIN(amount, sizeof(rndNum)); + memcpy(entropy, &rndNum, ret); + } } - return (OK) ? (int32_t)amount : -1; + return ret; } diff --git a/src/tpm2/PlatformData.c b/src/tpm2/PlatformData.c index 264da085..010a1716 100644 --- a/src/tpm2/PlatformData.c +++ b/src/tpm2/PlatformData.c @@ -81,9 +81,9 @@ clock_t s_tpmTime; unsigned char s_locality; /* From Power.c */ BOOL s_powerLost; -/* From Entropy.c */ +/* From Entropy.c This values is used to determine if the entropy generator is broken. If two + consecutive values are the same, then the entropy generator is considered to be broken.*/ uint32_t lastEntropy; -int firstValue; /* From NVMem.c */ #ifdef VTPM # undef FILE_BACKED_NV diff --git a/src/tpm2/PlatformData.h b/src/tpm2/PlatformData.h index ff67f53c..3a711db5 100644 --- a/src/tpm2/PlatformData.h +++ b/src/tpm2/PlatformData.h @@ -132,7 +132,6 @@ extern BOOL s_physicalPresence; extern BOOL s_powerLost; /* From Entropy.c */ extern uint32_t lastEntropy; -extern int firstValue; #endif // _PLATFORM_DATA_H_