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

Commit 59910de1 authored by Brian Delwiche's avatar Brian Delwiche Committed by Android (Google) Code Review
Browse files

Merge changes from topic "change-25815926" into main

* changes:
  Disallow connect with key length downgrade
  Disallow connect with Secure Connections downgrade
  Add support for checking security downgrade
parents fd6bb619 27a98dc0
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -212,6 +212,14 @@ static bool prop2cfg(const RawAddress* remote_bd_addr, bt_property_t* prop) {
      value[prop->len] = '\0';
      btif_config_set_str(bdstr, BTIF_STORAGE_KEY_DIS_MODEL_NUM, value);
    } break;
    case BT_PROPERTY_REMOTE_SECURE_CONNECTIONS_SUPPORTED:
      btif_config_set_int(bdstr, BTIF_STORAGE_KEY_SECURE_CONNECTIONS_SUPPORTED,
                          *(uint8_t*)prop->val);
      break;
    case BT_PROPERTY_REMOTE_MAX_SESSION_KEY_SIZE:
      btif_config_set_int(bdstr, BTIF_STORAGE_KEY_MAX_SESSION_KEY_SIZE,
                          *(uint8_t*)prop->val);
      break;
    default:
      LOG_ERROR("Unknown prop type:%d", prop->type);
      return false;
@@ -381,6 +389,26 @@ static bool cfg2prop(const RawAddress* remote_bd_addr, bt_property_t* prop) {
      }
    } break;

    case BT_PROPERTY_REMOTE_SECURE_CONNECTIONS_SUPPORTED: {
      int val;

      if (prop->len >= (int)sizeof(uint8_t)) {
        ret = btif_config_get_int(
            bdstr, BTIF_STORAGE_KEY_SECURE_CONNECTIONS_SUPPORTED, &val);
        *(uint8_t*)prop->val = (uint8_t)val;
      }
    } break;

    case BT_PROPERTY_REMOTE_MAX_SESSION_KEY_SIZE: {
      int val;

      if (prop->len >= (int)sizeof(uint8_t)) {
        ret = btif_config_get_int(bdstr, BTIF_STORAGE_KEY_MAX_SESSION_KEY_SIZE,
                                  &val);
        *(uint8_t*)prop->val = (uint8_t)val;
      }
    } break;

    default:
      LOG_ERROR("Unknown prop type:%d", prop->type);
      return false;
+14 −0
Original line number Diff line number Diff line
@@ -52,6 +52,8 @@ std::string bt_property_type_text(const bt_property_type_t& type) {
    CASE_RETURN_TEXT(BT_PROPERTY_REMOTE_MODEL_NUM);
    CASE_RETURN_TEXT(BT_PROPERTY_REMOTE_ADDR_TYPE);
    CASE_RETURN_TEXT(BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP);
    CASE_RETURN_TEXT(BT_PROPERTY_REMOTE_SECURE_CONNECTIONS_SUPPORTED);
    CASE_RETURN_TEXT(BT_PROPERTY_REMOTE_MAX_SESSION_KEY_SIZE);
  }
  return base::StringPrintf("Unknown [%d]", (int)type);
}
@@ -242,6 +244,18 @@ std::string bt_property_text(const bt_property_t& property) {

    case BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP:
      return base::StringPrintf("type:%s", bt_property_type_text(property.type).c_str());

    case BT_PROPERTY_REMOTE_SECURE_CONNECTIONS_SUPPORTED:
      return base::StringPrintf(
          "type:%s remote secure connections supported:%hhd",
          bt_property_type_text(property.type).c_str(),
          (*(uint8_t*)property.val));

    case BT_PROPERTY_REMOTE_MAX_SESSION_KEY_SIZE:
      return base::StringPrintf(
          "type:%s remote max session key size:%hhd",
          bt_property_type_text(property.type).c_str(),
          (*(uint8_t*)property.val));
  }
  return std::string("Unknown");
}
+2 −0
Original line number Diff line number Diff line
@@ -91,6 +91,7 @@
#define BTIF_STORAGE_KEY_LINK_KEY "LinkKey"
#define BTIF_STORAGE_KEY_LINK_KEY_TYPE "LinkKeyType"
#define BTIF_STORAGE_KEY_LOCAL_IO_CAPS "LocalIOCaps"
#define BTIF_STORAGE_KEY_MAX_SESSION_KEY_SIZE "MaxSessionKeySize"
#define BTIF_STORAGE_KEY_METRICS_ID_KEY "MetricsId"
#define BTIF_STORAGE_KEY_METRICS_SALT_256BIT "Salt256Bit"
#define BTIF_STORAGE_KEY_NAME "Name"
@@ -107,6 +108,7 @@
#define BTIF_STORAGE_KEY_SDP_DI_MANUFACTURER "SdpDiManufacturer"
#define BTIF_STORAGE_KEY_SDP_DI_MODEL "SdpDiModel"
#define BTIF_STORAGE_KEY_SDP_DI_VENDOR_ID_SRC "SdpDiVendorIdSource"
#define BTIF_STORAGE_KEY_SECURE_CONNECTIONS_SUPPORTED "SecureConnectionsSupported"
#define BTIF_STORAGE_KEY_TIMESTAMP "Timestamp"
#define BTIF_STORAGE_KEY_VENDOR_ID "VendorId"
#define BTIF_STORAGE_KEY_VENDOR_ID_SOURCE "VendorIdSource"
+14 −0
Original line number Diff line number Diff line
@@ -403,6 +403,20 @@ typedef enum {
   */
  BT_PROPERTY_REMOTE_ADDR_TYPE,

  /**
   * Description - Whether remote device supports Secure Connections mode
   * Access mode - GET and SET.
   * Data Type - uint8_t.
   */
  BT_PROPERTY_REMOTE_SECURE_CONNECTIONS_SUPPORTED,

  /**
   * Description - Maximum observed session key for remote device
   * Access mode - GET and SET.
   * Data Type - uint8_t.
   */
  BT_PROPERTY_REMOTE_MAX_SESSION_KEY_SIZE,

  BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP = 0xFF,
} bt_property_type_t;

+182 −17
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@

#include "stack/btm/btm_sec.h"

#include <android_bluetooth_flags.h>
#include <base/functional/bind.h>
#include <base/strings/stringprintf.h>

@@ -250,6 +251,110 @@ static tBTM_SEC_DEV_REC* btm_sec_find_dev_by_sec_state(uint8_t state) {
  return nullptr;
}

/*******************************************************************************
 *
 * Function         btm_sec_is_device_sc_downgrade
 *
 * Description      Check for a stored device record matching the candidate
 *                  device, and return true if the stored device has reported
 *                  that it supports Secure Connections mode and the candidate
 *                  device reports that it does not.  Otherwise, return false.
 *
 * Returns          bool
 *
 ******************************************************************************/
static bool btm_sec_is_device_sc_downgrade(uint16_t hci_handle,
                                           bool secure_connections_supported) {
  if (secure_connections_supported) return false;

  tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(hci_handle);
  if (p_dev_rec == nullptr) return false;

  uint8_t property_val = 0;
  bt_property_t property = {
      .type = BT_PROPERTY_REMOTE_SECURE_CONNECTIONS_SUPPORTED,
      .len = sizeof(uint8_t),
      .val = &property_val};

  bt_status_t cached =
      btif_storage_get_remote_device_property(&p_dev_rec->bd_addr, &property);

  if (cached == BT_STATUS_FAIL) return false;

  return (bool)property_val;
}

/*******************************************************************************
 *
 * Function         btm_sec_store_device_sc_support
 *
 * Description      Save Secure Connections support for this device to file
 *
 ******************************************************************************/

static void btm_sec_store_device_sc_support(uint16_t hci_handle,
                                            bool secure_connections_supported) {
  tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(hci_handle);
  if (p_dev_rec == nullptr) return;

  uint8_t property_val = (uint8_t)secure_connections_supported;
  bt_property_t property = {
      .type = BT_PROPERTY_REMOTE_SECURE_CONNECTIONS_SUPPORTED,
      .len = sizeof(uint8_t),
      .val = &property_val};

  btif_storage_set_remote_device_property(&p_dev_rec->bd_addr, &property);
}

/*******************************************************************************
 *
 * Function         btm_sec_is_session_key_size_downgrade
 *
 * Description      Check if there is a stored device record matching this
 *                  handle, and return true if the stored record has a lower
 *                  session key size than the candidate device.
 *
 * Returns          bool
 *
 ******************************************************************************/
static bool btm_sec_is_session_key_size_downgrade(uint16_t hci_handle,
                                                  uint8_t key_size) {
  tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(hci_handle);
  if (p_dev_rec == nullptr) return false;

  uint8_t property_val = 0;
  bt_property_t property = {.type = BT_PROPERTY_REMOTE_MAX_SESSION_KEY_SIZE,
                            .len = sizeof(uint8_t),
                            .val = &property_val};

  bt_status_t cached =
      btif_storage_get_remote_device_property(&p_dev_rec->bd_addr, &property);

  if (cached == BT_STATUS_FAIL) return false;

  return property_val > key_size;
}

/*******************************************************************************
 *
 * Function         btm_sec_update_session_key_size
 *
 * Description      Store the max session key size to disk, if possible.
 *
 ******************************************************************************/
static void btm_sec_update_session_key_size(uint16_t hci_handle,
                                            uint8_t key_size) {
  tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(hci_handle);
  if (p_dev_rec == nullptr) return;

  uint8_t property_val = key_size;
  bt_property_t property = {.type = BT_PROPERTY_REMOTE_MAX_SESSION_KEY_SIZE,
                            .len = sizeof(uint8_t),
                            .val = &property_val};

  btif_storage_set_remote_device_property(&p_dev_rec->bd_addr, &property);
}

/*******************************************************************************
 *
 * Function         access_secure_service_from_temp_bond
@@ -3378,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 */);
@@ -3399,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() ||
@@ -3417,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));
    }
  }
}
/*******************************************************************************
@@ -4014,6 +4159,14 @@ void btm_sec_link_key_notification(const RawAddress& p_bda,
    }
  }

  if (IS_FLAG_ENABLED(bluffs_mitigation) &&
      p_dev_rec->sec_rec.is_bond_type_persistent() &&
      (p_dev_rec->is_device_type_br_edr() ||
       p_dev_rec->is_device_type_dual_mode())) {
    btm_sec_store_device_sc_support(p_dev_rec->get_br_edr_hci_handle(),
                                    p_dev_rec->SupportsSecureConnections());
  }

  /* If name is not known at this point delay calling callback until the name is
   */
  /* resolved. Unless it is a HID Device and we really need to send all link
@@ -5035,6 +5188,18 @@ void btm_sec_set_peer_sec_caps(uint16_t hci_handle, bool ssp_supported,
  tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(hci_handle);
  if (p_dev_rec == nullptr) return;

  if (IS_FLAG_ENABLED(bluffs_mitigation)) {
    // Drop the connection here if the remote attempts to downgrade from Secure
    // Connections mode.
    if (btm_sec_is_device_sc_downgrade(hci_handle, sc_supported)) {
      acl_set_disconnect_reason(HCI_ERR_HOST_REJECT_SECURITY);
      btm_sec_send_hci_disconnect(
          p_dev_rec, HCI_ERR_AUTH_FAILURE, hci_handle,
          "attempted to downgrade from Secure Connections mode");
      return;
    }
  }

  p_dev_rec->remote_feature_received = true;
  p_dev_rec->remote_supports_hci_role_switch = hci_role_switch_supported;