The key derivation done by the FMC (label "rt_alias_cdi") is not conformant with the HMAC-SHA-384 specification. The HMAC computation only includes the first HMAC block, and is missing a second block which includes padding and a length suffix. This is not believed to be a security issue, as (by luck) all measurements are in the first block. If circumstances were slightly different, the consequences to these mistakes could have been a lot worse, so a post-mortem is necessary.
Background
Issue #1520 was filed, noting that the rt-alias public key differed between the RTL and the sw-emulator. This occurred because the driver/hardware was ignoring all blocks except for the first one in the derivation, but the sw-emulator implementation processed all blocks "correctly".
Causes
When consuming keys from the keyvault, the combination of the HMAC peripheral and driver only include the first 128-byte data block in the computation. The multi-block case is decently well tested by driver tests when operating on data and keys supplied and retrieved by the CPU, but when operating with keys supplied by (and result written to) the key-vault, the hardware clears the key after processing the first block, and subsequent blocks are ignored. This behavior was not called out in the hardware spec. I think folks assumed there would never be a need for multi-block HMAC for key derivation; and there wasn't, until somebody tweaked the derivation logic to use HKDF, which expanded the data beyond what would fit in a single block. I believe the systemic root causes are miscommunication between the hardware and firmware teams, and missing validation at several layers of the stack:
hardware: missing validation for the multi-block HMAC key-vault use case.
hardware spec: missing documentation of how the HMAC/key-vault multi-block usage differed from the non-key-vault usage.
firmware: missing multi-block HMAC key-vault driver test case (this is somewhat tricky because the direct results of the computation are kept secret from the CPU)
firmware: missing assertion in end-to-end tests to independently derive the rt-alias-key from UDS and measurements and confirm it matched the public key in the cert.
I have confirmed in PR #1528 that reloading the key from the keyvault and reprogramming the destination registers after each block works around this multi-block issue in the driver.
What went well?
The ROM was not affected. The smoke-tests independently confirm the derivation of the ROM-generated fmc-alias-key from the UDS and measurements.
What went wrong?
Validation at several layers of the stack failed to notice this issue.
Where we got lucky
The sw-emulator HMAC implementation diverged from the RTL implementation, and somebody noticed the derivations weren't consistent.
The ignored HMAC block doesn't include any actual measurements (it just has padding + length):
The key derivation done by the FMC (label "rt_alias_cdi") is not conformant with the HMAC-SHA-384 specification. The HMAC computation only includes the first HMAC block, and is missing a second block which includes padding and a length suffix. This is not believed to be a security issue, as (by luck) all measurements are in the first block. If circumstances were slightly different, the consequences to these mistakes could have been a lot worse, so a post-mortem is necessary.
Background
Issue #1520 was filed, noting that the rt-alias public key differed between the RTL and the sw-emulator. This occurred because the driver/hardware was ignoring all blocks except for the first one in the derivation, but the sw-emulator implementation processed all blocks "correctly".
Causes
When consuming keys from the keyvault, the combination of the HMAC peripheral and driver only include the first 128-byte data block in the computation. The multi-block case is decently well tested by driver tests when operating on data and keys supplied and retrieved by the CPU, but when operating with keys supplied by (and result written to) the key-vault, the hardware clears the key after processing the first block, and subsequent blocks are ignored. This behavior was not called out in the hardware spec. I think folks assumed there would never be a need for multi-block HMAC for key derivation; and there wasn't, until somebody tweaked the derivation logic to use HKDF, which expanded the data beyond what would fit in a single block. I believe the systemic root causes are miscommunication between the hardware and firmware teams, and missing validation at several layers of the stack:
hardware: missing validation for the multi-block HMAC key-vault use case.
hardware spec: missing documentation of how the HMAC/key-vault multi-block usage differed from the non-key-vault usage.
firmware: missing multi-block HMAC key-vault driver test case (this is somewhat tricky because the direct results of the computation are kept secret from the CPU)
firmware: missing assertion in end-to-end tests to independently derive the rt-alias-key from UDS and measurements and confirm it matched the public key in the cert.
I have confirmed in PR #1528 that reloading the key from the keyvault and reprogramming the destination registers after each block works around this multi-block issue in the driver.
What went well?
What went wrong?
Where we got lucky
The sw-emulator HMAC implementation diverged from the RTL implementation, and somebody noticed the derivations weren't consistent.
The ignored HMAC block doesn't include any actual measurements (it just has padding + length):
Action Plan
(Do not mark this bug completed until all tasks are complete)