On 07/11/19 11:25, Ard Biesheuvel wrote: >> This looks problematic on QEMU. Entropy is a valuable resource, and >> whatever resource SMM drivers depend on, should not be possible for e.g. >> a 3rd party UEFI driver (or even for the runtime OS) to exhaust. >> Therefore, it's not *only* the case that SMM drivers must not consume >> EFI_RNG_PROTOCOL (which exists at a less critical privilege level, i.e. >> outside of SMM/SMRAM), but also that SMM drivers must not depend on the >> same piece of *hardware* that feeds EFI_RNG_PROTOCOL. >> > The typical model is to seed a DRBG [deterministic pseudorandom > sequence generator] using a sufficient amount of high quality entropy. > Once you have done that, it is rather hard to exhaust a DRBG - it is a > mathematical construction that is designed to last for a long time (<= > 2^48 invocations [not bytes] according to the NIST spec), after which > it does not degrade although it may have generated so much output that > its internal state may be inferred if you have captured enough of it > (which is a rather theoretical issue IMHO) > > The problem is that using the output of a DRBG as a seed is > non-trivial - the spec describes ways to do this, but wiring > virtio-rng to a DRBG in the host and using its output to seed a DRBG > in the guest is slighly problematic. > > So it seems to me that the correct way to model this is to make the > host's true entropy source a shared resource like any other. >
Yes, I would make SMM use a cryptographic pseudo-random number generator and seed it from virtio-rng from DXE, way before the OS starts and can "attack" it. Once you've gotten a seed, you can create a CSPRNG with a stream cipher such as ChaCha20, which is literally 30 lines of code. Paolo #define ROTL(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) #define QR(a, b, c, d) ( \ a += b, d ^= a, d = ROTL(d,16), \ c += d, b ^= c, b = ROTL(b,12), \ a += b, d ^= a, d = ROTL(d, 8), \ c += d, b ^= c, b = ROTL(b, 7)) #define ROUNDS 20 // initial state: // in[0] = 0x65787061 // in[1] = 0x6e642033 // in[2] = 0x322d6279 // in[3] = 0x7465206b // in[4]..in[11] = key (seed) // in[12]..in[13] = 0 // in[14]..in[15] = nonce, can probably use RDTSC? static uint32_t in[16]; uint32_t chacha_rng(void) { int i; static uint32_t x[16], p; if (p < 16) return in[p++] + x[p++]; if (++in[12] == 0) ++in[13]; for (i = 0; i < 16; ++i) x[i] = in[i]; // 10 loops × 2 rounds/loop = 20 rounds for (i = 0; i < ROUNDS; i += 2) { // Odd round QR(x[0], x[4], x[ 8], x[12]); // column 0 QR(x[1], x[5], x[ 9], x[13]); // column 1 QR(x[2], x[6], x[10], x[14]); // column 2 QR(x[3], x[7], x[11], x[15]); // column 3 // Even round QR(x[0], x[5], x[10], x[15]); // diagonal 1 (main diagonal) QR(x[1], x[6], x[11], x[12]); // diagonal 2 QR(x[2], x[7], x[ 8], x[13]); // diagonal 3 QR(x[3], x[4], x[ 9], x[14]); // diagonal 4 } p = 1; return in[0] + x[0]; }