fix off-by-one in update_client_pin_if_verified()

The code that validated new PIN length checks if new PIN is between 4 and 63
bytes long, instead of between 4 and 64 as it should. This could allow an
attacker to decrypt the 64-th byte of an encrypted message without knowing
the shared secret key, assuming he can bypass the HMAC memcmp check (which is
not too likely).

Reasoning:
  The authenticator decrypts the given PIN, and a user/attacker can tell if the
  given decrypted PIN length is correct or not from the returned error, this is
  a padding oracle.
  If the check were if the new pin is between was between 4 and 64 this wouln't
  be a problem, since 64 is a multiple of the block size (16), and since the
  message is padded to block multiples, all 64-byte long new PINs would be
  accepted. The next possible length is 80 bytes, and the only way an 80-bytes
  new PIN message would be accepted is if the last 16 bytes are zero, which is
  impossibly unlikely (2 ^ -16 random chance), so the padding oracle won't give
  an attacker anything.
  Since the actual check is if the PIN is between 4 and 63, if you send a 64
  byte new PIN message, it would be accepted only if the last byte was
  decrypted to zero, and fail otherwise.
  Since the authenticator uses CBC mode of operation, it is possible the brute-
  force the last byte of the previous block (i.e. the 48-th byte) until the
  last byte is zero, then you know the last byte is zero, so the decrypted last
  byte is the encrypted 48-th byte.
pull/559/head
Daniel Cohen Hillel 2021-06-17 16:55:47 -04:00
rodzic 2884f95ff4
commit 56c1a353a6
1 zmienionych plików z 1 dodań i 1 usunięć

Wyświetl plik

@ -2023,7 +2023,7 @@ uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platfor
ret = trailing_zeros(pinEnc, NEW_PIN_ENC_MIN_SIZE - 1);
ret = NEW_PIN_ENC_MIN_SIZE - ret;
if (ret < NEW_PIN_MIN_SIZE || ret >= NEW_PIN_MAX_SIZE)
if (ret < NEW_PIN_MIN_SIZE || ret > NEW_PIN_MAX_SIZE)
{
printf2(TAG_ERR,"new PIN is too short or too long [%d bytes]\n", ret);
return CTAP2_ERR_PIN_POLICY_VIOLATION;