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

Commit ec6e086f authored by Brian Delwiche's avatar Brian Delwiche
Browse files

Add support for checking security downgrade

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

Future CLs will add checks during connection.  This CL adds the
functions that will be needed to perform those checks and the necessary
mocks.
Currently supported checks are : IO capabilities (must be an exact match),
Secure Connections capability (must not be a downgrade), and session key
length (must not be a downgrade).  Maximum session key length, which was
previously not cached, has been added to the device security manager
cache.

To QA: This CL is a logical no-op by itself.  Tests should be performed as described in ag/25815924 and ag/25815925/

Bug: 314331379
Test: m libbluetooth
Tag: #security
Ignore-AOSP-First: Security
Change-Id: I3cd1db300be68d15cb09bdabea711199fcf748da
parent 551d3861
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;

+104 −0
Original line number Diff line number Diff line
@@ -250,6 +250,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