1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-16 03:18:09 +00:00

Increment PIN fail counter after deriving the KEK and KEIV from the PIN.

This commit is contained in:
Andrew Kozlik 2019-03-20 14:49:19 +01:00
parent 511fc205b2
commit d710db50fe

View File

@ -725,34 +725,26 @@ void storage_lock(void)
memzero(authentication_sum, sizeof(authentication_sum)); memzero(authentication_sum, sizeof(authentication_sum));
} }
static secbool decrypt_dek(uint32_t pin) static secbool decrypt_dek(const uint8_t *kek, const uint8_t *keiv)
{ {
const void *buffer = NULL; const void *buffer = NULL;
uint16_t len = 0; uint16_t len = 0;
if (sectrue != initialized || sectrue != norcow_get(EDEK_PVC_KEY, &buffer, &len) || len != RANDOM_SALT_SIZE + KEYS_SIZE + PVC_SIZE) { if (sectrue != initialized || sectrue != norcow_get(EDEK_PVC_KEY, &buffer, &len) || len != RANDOM_SALT_SIZE + KEYS_SIZE + PVC_SIZE) {
memzero(&pin, sizeof(pin));
handle_fault("no EDEK"); handle_fault("no EDEK");
return secfalse; return secfalse;
} }
const uint8_t *salt = (const uint8_t*) buffer;
const uint8_t *ekeys = (const uint8_t*) buffer + RANDOM_SALT_SIZE; const uint8_t *ekeys = (const uint8_t*) buffer + RANDOM_SALT_SIZE;
const uint32_t *pvc = (const uint32_t*) buffer + (RANDOM_SALT_SIZE + KEYS_SIZE)/sizeof(uint32_t); const uint32_t *pvc = (const uint32_t*) buffer + (RANDOM_SALT_SIZE + KEYS_SIZE)/sizeof(uint32_t);
_Static_assert(((RANDOM_SALT_SIZE + KEYS_SIZE) & 3) == 0, "PVC unaligned"); _Static_assert(((RANDOM_SALT_SIZE + KEYS_SIZE) & 3) == 0, "PVC unaligned");
_Static_assert((PVC_SIZE & 3) == 0, "PVC size unaligned"); _Static_assert((PVC_SIZE & 3) == 0, "PVC size unaligned");
uint8_t kek[SHA256_DIGEST_LENGTH];
uint8_t keiv[SHA256_DIGEST_LENGTH];
uint8_t keys[KEYS_SIZE]; uint8_t keys[KEYS_SIZE];
uint8_t tag[POLY1305_TAG_SIZE] __attribute__((aligned(sizeof(uint32_t)))); uint8_t tag[POLY1305_TAG_SIZE] __attribute__((aligned(sizeof(uint32_t))));
chacha20poly1305_ctx ctx; chacha20poly1305_ctx ctx;
// Decrypt the data encryption key and the storage authentication key and check the PIN verification code. // Decrypt the data encryption key and the storage authentication key and check the PIN verification code.
derive_kek(pin, salt, kek, keiv);
memzero(&pin, sizeof(pin));
rfc7539_init(&ctx, kek, keiv); rfc7539_init(&ctx, kek, keiv);
memzero(kek, sizeof(kek));
memzero(keiv, sizeof(keiv));
chacha20poly1305_decrypt(&ctx, ekeys, keys, KEYS_SIZE); chacha20poly1305_decrypt(&ctx, ekeys, keys, KEYS_SIZE);
rfc7539_finish(&ctx, 0, KEYS_SIZE, tag); rfc7539_finish(&ctx, 0, KEYS_SIZE, tag);
memzero(&ctx, sizeof(ctx)); memzero(&ctx, sizeof(ctx));
@ -818,11 +810,23 @@ static secbool unlock(uint32_t pin)
} }
} }
// Read the random salt from EDEK_PVC_KEY and use it to derive the KEK and KEIV from the PIN.
const void *salt = NULL;
uint16_t len = 0;
if (sectrue != initialized || sectrue != norcow_get(EDEK_PVC_KEY, &salt, &len) || len != RANDOM_SALT_SIZE + KEYS_SIZE + PVC_SIZE) {
memzero(&pin, sizeof(pin));
handle_fault("no EDEK");
return secfalse;
}
uint8_t kek[SHA256_DIGEST_LENGTH];
uint8_t keiv[SHA256_DIGEST_LENGTH];
derive_kek(pin, (const uint8_t*) salt, kek, keiv);
memzero(&pin, sizeof(pin));
// First, we increase PIN fail counter in storage, even before checking the // First, we increase PIN fail counter in storage, even before checking the
// PIN. If the PIN is correct, we reset the counter afterwards. If not, we // PIN. If the PIN is correct, we reset the counter afterwards. If not, we
// check if this is the last allowed attempt. // check if this is the last allowed attempt.
if (sectrue != storage_pin_fails_increase()) { if (sectrue != storage_pin_fails_increase()) {
memzero(&pin, sizeof(pin));
return secfalse; return secfalse;
} }
@ -833,7 +837,8 @@ static secbool unlock(uint32_t pin)
return secfalse; return secfalse;
} }
if (sectrue != decrypt_dek(pin)) { // Check that the PIN was correct.
if (sectrue != decrypt_dek(kek, keiv)) {
// Wipe storage if too many failures // Wipe storage if too many failures
wait_random(); wait_random();
if (ctr + 1 >= PIN_MAX_TRIES) { if (ctr + 1 >= PIN_MAX_TRIES) {
@ -842,7 +847,9 @@ static secbool unlock(uint32_t pin)
} }
return secfalse; return secfalse;
} }
memzero(&pin, sizeof(pin)); memzero(kek, sizeof(kek));
memzero(keiv, sizeof(keiv));
unlocked = sectrue; unlocked = sectrue;
// Finally set the counter to 0 to indicate success. // Finally set the counter to 0 to indicate success.