Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 27a98dc0 authored by Brian Delwiche's avatar Brian Delwiche
Browse files

Disallow connect with key length downgrade

As a guard against the BLUFFS attack, check security parameters of
incoming connections against cached values and disallow connection if
these parameters are downgraded or changed from their cached values.

This CL adds the connection-time check for session key length.

Bug: 314331379
Test: m libbluetooth
Test: manual

To test, please validate that bonding can be established and
reestablished against devices with session key lengths of 7 and 16 bits,
that session key lengths of less than 7 bits are refused, and that basic
LE bonding functionality still works.  If it is possible to configure a
remote device to establish a bond with a session key length of 16 bits
and then reduce that key length to <16 bits before reconnection, this
should fail.

Tag: #security
Ignore-AOSP-First: Security
Change-Id: I0f3c1b46e103e4bf7d9cd3240168faaaa271cebc
parent a7b20aa0
Loading
Loading
Loading
Loading
+57 −17
Original line number Diff line number Diff line
@@ -3483,6 +3483,22 @@ static void read_encryption_key_size_complete_after_encryption_change(
    return;
  }

  if (IS_FLAG_ENABLED(bluffs_mitigation)) {
    if (btm_sec_is_session_key_size_downgrade(handle, key_size)) {
      LOG_ERROR(
          "encryption key size lower than cached value, disconnecting. "
          "handle: 0x%x attempted key size: %d",
          handle, key_size);
      acl_disconnect_from_handle(
          handle, HCI_ERR_HOST_REJECT_SECURITY,
          "stack::btu::btu_hcif::read_encryption_key_size_complete_after_"
          "encryption_change Key Size Downgrade");
      return;
    }

    btm_sec_update_session_key_size(handle, key_size);
  }

  // good key size - succeed
  btm_acl_encrypt_change(handle, static_cast<tHCI_STATUS>(status),
                         1 /* enable */);
@@ -3504,6 +3520,28 @@ void smp_cancel_start_encryption_attempt();
 ******************************************************************************/
void btm_sec_encryption_change_evt(uint16_t handle, tHCI_STATUS status,
                                   uint8_t encr_enable) {
  if (IS_FLAG_ENABLED(bluffs_mitigation)) {
    if (status != HCI_SUCCESS || encr_enable == 0 ||
        BTM_IsBleConnection(handle) ||
        !controller_get_interface()->supports_read_encryption_key_size()) {
      if (status == HCI_ERR_CONNECTION_TOUT) {
        smp_cancel_start_encryption_attempt();
        return;
      }

      btm_acl_encrypt_change(handle, static_cast<tHCI_STATUS>(status),
                             encr_enable);
      btm_sec_encrypt_change(handle, static_cast<tHCI_STATUS>(status),
                             encr_enable);
    } else {
      btsnd_hcic_read_encryption_key_size(
          handle,
          base::Bind(
              &read_encryption_key_size_complete_after_encryption_change));
    }
  } else {
    // This block added to ensure matching code flow with the bluffs_mitigation
    // flag off.  The entire block should be removed when the flag is.
    if (status != HCI_SUCCESS || encr_enable == 0 ||
        BTM_IsBleConnection(handle) ||
        !controller_get_interface()->supports_read_encryption_key_size() ||
@@ -3522,7 +3560,9 @@ void btm_sec_encryption_change_evt(uint16_t handle, tHCI_STATUS status,
    } else {
      btsnd_hcic_read_encryption_key_size(
          handle,
        base::Bind(&read_encryption_key_size_complete_after_encryption_change));
          base::Bind(
              &read_encryption_key_size_complete_after_encryption_change));
    }
  }
}
/*******************************************************************************