summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--system/btif/src/btif_storage.cc30
-rw-r--r--system/include/hardware/bluetooth.h14
-rw-r--r--system/stack/btm/btm_sec.cc120
-rw-r--r--system/stack/btm/btm_sec.h23
-rw-r--r--system/stack/btu/btu_hcif.cc14
-rw-r--r--system/stack/include/sec_hci_link_interface.h3
-rw-r--r--system/test/headless/bt_property.cc6
-rw-r--r--system/test/mock/mock_stack_btm_sec.cc9
8 files changed, 219 insertions, 0 deletions
diff --git a/system/btif/src/btif_storage.cc b/system/btif/src/btif_storage.cc
index 4fd1fdaf55..682ac838ef 100644
--- a/system/btif/src/btif_storage.cc
+++ b/system/btif/src/btif_storage.cc
@@ -85,6 +85,7 @@ using bluetooth::Uuid;
#define BTIF_STORAGE_KEY_ADAPTER_NAME "Name"
#define BTIF_STORAGE_KEY_ADAPTER_SCANMODE "ScanMode"
#define BTIF_STORAGE_KEY_LOCAL_IO_CAPS "LocalIOCaps"
+#define BTIF_STORAGE_KEY_MAX_SESSION_KEY_SIZE "MaxSessionKeySize"
#define BTIF_STORAGE_KEY_ADAPTER_DISC_TIMEOUT "DiscoveryTimeout"
#define BTIF_STORAGE_KEY_GATT_CLIENT_SUPPORTED "GattClientSupportedFeatures"
#define BTIF_STORAGE_KEY_GATT_CLIENT_DB_HASH "GattClientDatabaseHash"
@@ -94,6 +95,8 @@ using bluetooth::Uuid;
#define BTIF_STORAGE_PATH_VENDOR_ID "VendorId"
#define BTIF_STORAGE_PATH_PRODUCT_ID "ProductId"
#define BTIF_STORAGE_PATH_VERSION "ProductVersion"
+#define BTIF_STORAGE_KEY_SECURE_CONNECTIONS_SUPPORTED \
+ "SecureConnectionsSupported"
/* This is a local property to add a device found */
#define BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP 0xFF
@@ -223,6 +226,14 @@ static int prop2cfg(const RawAddress* remote_bd_addr, bt_property_t* prop) {
info->product_id);
btif_config_set_int(bdstr, BTIF_STORAGE_PATH_VERSION, info->version);
} 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;
case BT_PROPERTY_REMOTE_MODEL_NUM: {
strncpy(value, (char*)prop->val, prop->len);
value[prop->len] = '\0';
@@ -385,6 +396,25 @@ static int cfg2prop(const RawAddress* remote_bd_addr, bt_property_t* prop) {
ret = false;
}
} 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:
BTIF_TRACE_ERROR("Unknow prop type:%d", prop->type);
diff --git a/system/include/hardware/bluetooth.h b/system/include/hardware/bluetooth.h
index 62526cedf3..d2cfbbb0ad 100644
--- a/system/include/hardware/bluetooth.h
+++ b/system/include/hardware/bluetooth.h
@@ -403,6 +403,20 @@ typedef enum {
*/
BT_PROPERTY_ENC_KEY_MATERIAL,
+ /**
+ * 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;
diff --git a/system/stack/btm/btm_sec.cc b/system/stack/btm/btm_sec.cc
index 9a363568f9..220c32f154 100644
--- a/system/stack/btm/btm_sec.cc
+++ b/system/stack/btm/btm_sec.cc
@@ -232,6 +232,109 @@ static bool btm_dev_16_digit_authenticated(tBTM_SEC_DEV_REC* p_dev_rec) {
/*******************************************************************************
*
+ * 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
+ *
+ ******************************************************************************/
+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.
+ *
+ ******************************************************************************/
+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
*
* Description a utility function to test whether an access to
@@ -4065,6 +4168,13 @@ void btm_sec_link_key_notification(const RawAddress& p_bda,
}
}
+ if (p_dev_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
@@ -5144,6 +5254,16 @@ 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;
+ // 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;
diff --git a/system/stack/btm/btm_sec.h b/system/stack/btm/btm_sec.h
index 2647f0764d..6596f6fd15 100644
--- a/system/stack/btm/btm_sec.h
+++ b/system/stack/btm/btm_sec.h
@@ -789,5 +789,28 @@ void btm_sec_set_peer_sec_caps(uint16_t hci_handle, bool ssp_supported,
void btm_sec_cr_loc_oob_data_cback_event(const RawAddress& address,
tSMP_LOC_OOB_DATA loc_oob_data);
+/*******************************************************************************
+ *
+ * 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
+ *
+ ******************************************************************************/
+bool btm_sec_is_session_key_size_downgrade(uint16_t hci_handle,
+ uint8_t key_size);
+
+/*******************************************************************************
+ *
+ * Function btm_sec_update_session_key_size
+ *
+ * Description Store the max session key size to disk, if possible.
+ *
+ ******************************************************************************/
+void btm_sec_update_session_key_size(uint16_t hci_handle, uint8_t key_size);
+
// Return DEV_CLASS (uint8_t[3]) of bda. If record doesn't exist, create one.
const uint8_t* btm_get_dev_class(const RawAddress& bda);
diff --git a/system/stack/btu/btu_hcif.cc b/system/stack/btu/btu_hcif.cc
index 605e95e15d..c71534499d 100644
--- a/system/stack/btu/btu_hcif.cc
+++ b/system/stack/btu/btu_hcif.cc
@@ -918,6 +918,20 @@ static void read_encryption_key_size_complete_after_encryption_change(uint8_t st
return;
}
+ 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 */);
diff --git a/system/stack/include/sec_hci_link_interface.h b/system/stack/include/sec_hci_link_interface.h
index dce3c479fd..1fecde74ed 100644
--- a/system/stack/include/sec_hci_link_interface.h
+++ b/system/stack/include/sec_hci_link_interface.h
@@ -37,6 +37,8 @@ void btm_sec_auth_complete(uint16_t handle, tHCI_STATUS status);
void btm_sec_disconnected(uint16_t handle, tHCI_STATUS reason, std::string);
void btm_sec_encrypt_change(uint16_t handle, tHCI_STATUS status,
uint8_t encr_enable);
+bool btm_sec_is_session_key_size_downgrade(uint16_t hci_handle,
+ uint8_t key_size);
void btm_sec_link_key_notification(const RawAddress& p_bda,
const Octet16& link_key, uint8_t key_type);
void btm_sec_link_key_request(const uint8_t* p_event);
@@ -46,4 +48,5 @@ void btm_sec_rmt_name_request_complete(const RawAddress* bd_addr,
const uint8_t* bd_name,
tHCI_STATUS status);
void btm_sec_update_clock_offset(uint16_t handle, uint16_t clock_offset);
+void btm_sec_update_session_key_size(uint16_t hci_handle, uint8_t key_size);
void btm_simple_pair_complete(const uint8_t* p);
diff --git a/system/test/headless/bt_property.cc b/system/test/headless/bt_property.cc
index 5b6c2d5397..a599e3f53a 100644
--- a/system/test/headless/bt_property.cc
+++ b/system/test/headless/bt_property.cc
@@ -107,6 +107,12 @@ void process_property(const RawAddress& bd_addr, const bt_property_t* prop) {
case BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP:
LOG_CONSOLE("BT_PROPERTY_REMOTE_IS_COORDINATED_SET_MEMBER");
break;
+ case BT_PROPERTY_REMOTE_SECURE_CONNECTIONS_SUPPORTED:
+ LOG_CONSOLE("BT_PROPERTY_REMOTE_SECURE_CONNECTIONS_SUPPORTED");
+ break;
+ case BT_PROPERTY_REMOTE_MAX_SESSION_KEY_SIZE:
+ LOG_CONSOLE("BT_PROPERTY_REMOTE_MAX_SESSION_KEY_SIZE");
+ break;
default: {
LOG_CONSOLE("Unable to find BT property bd_addr:%s type:%d ptr:%p",
ADDRESS_TO_LOGGABLE_CSTR(bd_addr), prop->type, prop);
diff --git a/system/test/mock/mock_stack_btm_sec.cc b/system/test/mock/mock_stack_btm_sec.cc
index d24156e9a0..7819435b89 100644
--- a/system/test/mock/mock_stack_btm_sec.cc
+++ b/system/test/mock/mock_stack_btm_sec.cc
@@ -116,6 +116,11 @@ bool btm_sec_is_a_bonded_dev(const RawAddress& bda) {
inc_func_call_count(__func__);
return false;
}
+bool btm_sec_is_session_key_size_downgrade(uint16_t hci_handle,
+ uint8_t key_size) {
+ inc_func_call_count(__func__);
+ return false;
+}
bool is_sec_state_equal(void* data, void* context) {
inc_func_call_count(__func__);
return false;
@@ -312,6 +317,10 @@ void btm_sec_set_peer_sec_caps(uint16_t hci_handle, bool ssp_supported,
void btm_sec_update_clock_offset(uint16_t handle, uint16_t clock_offset) {
inc_func_call_count(__func__);
}
+void btm_sec_update_session_key_size(uint16_t hci_handle, uint8_t key_size) {
+ inc_func_call_count(__func__);
+}
+
void btm_simple_pair_complete(const uint8_t* p) {
inc_func_call_count(__func__);
}