From 99d572700d5d8f9405bbdd9ab75f3dde67eb2fae Mon Sep 17 00:00:00 2001 From: Chinmay Chhajed Date: Wed, 24 Jun 2020 15:23:56 +0530 Subject: [PATCH] Bluedroid: Authentication fixes in Legacy and Secure Connection. Prevent a remote device from doing a Bluetooth Impersonation Attack (BIAS) by: - Preventing remote device to downgrade secure connection feature mask. Secure connection feature mask should remain same or increase to enabled in link key generation and authentication. - Doing a mutual authentication during Legacy Authentication. --- components/bt/Kconfig | 13 ++ components/bt/bluedroid/bta/dm/bta_dm_act.c | 10 +- components/bt/bluedroid/bta/dm/bta_dm_api.c | 6 +- .../bt/bluedroid/bta/dm/include/bta_dm_int.h | 2 + .../bt/bluedroid/bta/include/bta/bta_api.h | 5 +- components/bt/bluedroid/btc/core/btc_dm.c | 24 +++- .../bt/bluedroid/btc/core/btc_storage.c | 16 ++- .../bluedroid/btc/include/btc/btc_storage.h | 4 +- components/bt/bluedroid/stack/btm/btm_acl.c | 68 +++++++---- components/bt/bluedroid/stack/btm/btm_dev.c | 3 +- .../bt/bluedroid/stack/btm/btm_devctl.c | 13 +- components/bt/bluedroid/stack/btm/btm_sec.c | 112 +++++++++++++++++- .../bt/bluedroid/stack/btm/include/btm_int.h | 15 +++ .../bluedroid/stack/include/stack/btm_api.h | 20 ++-- components/bt/include/esp_bt.h | 12 +- components/bt/lib | 2 +- 16 files changed, 273 insertions(+), 52 deletions(-) diff --git a/components/bt/Kconfig b/components/bt/Kconfig index a0f63c84e..8c9d53657 100644 --- a/components/bt/Kconfig +++ b/components/bt/Kconfig @@ -89,6 +89,19 @@ menu Bluetooth default BTDM_CTRL_AUTO_LATENCY if BTDM_CONTROLLER_MODE_BTDM default n + config BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT + bool "Legacy Authentication Vendor Specific Event Enable" + depends on BTDM_CONTROLLER_MODE_BR_EDR_ONLY || BTDM_CONTROLLER_MODE_BTDM + default y + help + To protect from BIAS attack during Legacy authentication, + Legacy authentication Vendor specific event should be enabled + + + config BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT_EFF + bool + default BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT if BTDM_CONTROLLER_MODE_BR_EDR_ONLY || BTDM_CONTROLLER_MODE_BTDM + default 0 config BTDM_CONTROLLER_BLE_MAX_CONN_EFF int diff --git a/components/bt/bluedroid/bta/dm/bta_dm_act.c b/components/bt/bluedroid/bta/dm/bta_dm_act.c index 99fd45cc8..0e1472057 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_act.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_act.c @@ -61,7 +61,7 @@ static void bta_dm_sdp_callback (UINT16 sdp_status); #if (SMP_INCLUDED == TRUE) static UINT8 bta_dm_authorize_cback (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name, UINT8 *service_name, UINT8 service_id, BOOLEAN is_originator); static UINT8 bta_dm_pin_cback (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name, BOOLEAN min_16_digit); -static UINT8 bta_dm_new_link_key_cback(BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name, LINK_KEY key, UINT8 key_type); +static UINT8 bta_dm_new_link_key_cback(BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name, LINK_KEY key, UINT8 key_type, BOOLEAN sc_support); static UINT8 bta_dm_authentication_complete_cback(BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name, int result); #endif ///SMP_INCLUDED == TRUE static void bta_dm_local_name_cback(BD_ADDR bd_addr); @@ -822,7 +822,7 @@ void bta_dm_add_device (tBTA_DM_MSG *p_data) if (!BTM_SecAddDevice (p_dev->bd_addr, p_dc, p_dev->bd_name, p_dev->features, trusted_services_mask, p_lc, p_dev->key_type, p_dev->io_cap, - p_dev->pin_length)) { + p_dev->pin_length, p_dev->sc_support)) { APPL_TRACE_ERROR ("BTA_DM: Error adding device %08x%04x", (p_dev->bd_addr[0] << 24) + (p_dev->bd_addr[1] << 16) + (p_dev->bd_addr[2] << 8) + p_dev->bd_addr[3], (p_dev->bd_addr[4] << 8) + p_dev->bd_addr[5]); @@ -2784,7 +2784,8 @@ static UINT8 bta_dm_pin_cback (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_ ** *******************************************************************************/ static UINT8 bta_dm_new_link_key_cback(BD_ADDR bd_addr, DEV_CLASS dev_class, - BD_NAME bd_name, LINK_KEY key, UINT8 key_type) + BD_NAME bd_name, LINK_KEY key, UINT8 key_type, + BOOLEAN sc_support) { tBTA_DM_SEC sec_event; tBTA_DM_AUTH_CMPL *p_auth_cmpl; @@ -2806,6 +2807,7 @@ static UINT8 bta_dm_new_link_key_cback(BD_ADDR bd_addr, DEV_CLASS dev_class, p_auth_cmpl->key_present = TRUE; p_auth_cmpl->key_type = key_type; p_auth_cmpl->success = TRUE; + p_auth_cmpl->sc_support = sc_support; memcpy(p_auth_cmpl->key, key, LINK_KEY_LEN); sec_event.auth_cmpl.fail_reason = HCI_SUCCESS; @@ -3083,6 +3085,7 @@ static void bta_dm_bl_change_cback (tBTM_BL_EVENT_DATA *p_data) switch (p_msg->event) { case BTM_BL_CONN_EVT: + p_msg->sc_downgrade = p_data->conn.sc_downgrade; p_msg->is_new = TRUE; bdcpy(p_msg->bd_addr, p_data->conn.p_bda); #if BLE_INCLUDED == TRUE @@ -3309,6 +3312,7 @@ void bta_dm_acl_change(tBTA_DM_MSG *p_data) APPL_TRACE_DEBUG("%s info: 0x%x", __func__, bta_dm_cb.device_list.peer_device[i].info); if (bta_dm_cb.p_sec_cback) { + conn.link_up.sc_downgrade = p_data->acl_change.sc_downgrade; bta_dm_cb.p_sec_cback(BTA_DM_LINK_UP_EVT, (tBTA_DM_SEC *)&conn); } } else { diff --git a/components/bt/bluedroid/bta/dm/bta_dm_api.c b/components/bt/bluedroid/bta/dm/bta_dm_api.c index 2eec142b7..82c4895cd 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_api.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_api.c @@ -586,6 +586,7 @@ void BTA_DmPasskeyReqReply(BOOLEAN accept, BD_ADDR bd_addr, UINT32 passkey) } } #endif ///BT_SSP_INCLUDED == TRUE +#endif ///SMP_INCLUDED == TRUE /******************************************************************************* ** ** Function BTA_DmAddDevice @@ -599,7 +600,8 @@ void BTA_DmPasskeyReqReply(BOOLEAN accept, BD_ADDR bd_addr, UINT32 passkey) *******************************************************************************/ void BTA_DmAddDevice(BD_ADDR bd_addr, DEV_CLASS dev_class, LINK_KEY link_key, tBTA_SERVICE_MASK trusted_mask, BOOLEAN is_trusted, - UINT8 key_type, tBTA_IO_CAP io_cap, UINT8 pin_length) + UINT8 key_type, tBTA_IO_CAP io_cap, UINT8 pin_length, + UINT8 sc_support) { tBTA_DM_API_ADD_DEVICE *p_msg; @@ -612,6 +614,7 @@ void BTA_DmAddDevice(BD_ADDR bd_addr, DEV_CLASS dev_class, LINK_KEY link_key, p_msg->tm = trusted_mask; p_msg->is_trusted = is_trusted; p_msg->io_cap = io_cap; + p_msg->sc_support = sc_support; if (link_key) { p_msg->link_key_known = TRUE; @@ -662,7 +665,6 @@ tBTA_STATUS BTA_DmRemoveDevice(BD_ADDR bd_addr, tBT_TRANSPORT transport) return BTA_SUCCESS; } -#endif ///SMP_INCLUDED == TRUE /******************************************************************************* ** diff --git a/components/bt/bluedroid/bta/dm/include/bta_dm_int.h b/components/bt/bluedroid/bta/dm/include/bta_dm_int.h index 23c2d6328..eebbe4a26 100644 --- a/components/bt/bluedroid/bta/dm/include/bta_dm_int.h +++ b/components/bt/bluedroid/bta/dm/include/bta_dm_int.h @@ -384,6 +384,7 @@ typedef struct { UINT8 new_role; BD_ADDR bd_addr; UINT8 hci_status; + BOOLEAN sc_downgrade; #if BLE_INCLUDED == TRUE UINT16 handle; tBT_TRANSPORT transport; @@ -425,6 +426,7 @@ typedef struct { BD_NAME bd_name; UINT8 features[BTA_FEATURE_BYTES_PER_PAGE * (BTA_EXT_FEATURES_PAGE_MAX + 1)]; UINT8 pin_length; + UINT8 sc_support; } tBTA_DM_API_ADD_DEVICE; /* data type for BTA_DM_API_REMOVE_ACL_EVT */ diff --git a/components/bt/bluedroid/bta/include/bta/bta_api.h b/components/bt/bluedroid/bta/include/bta/bta_api.h index c580433ba..0e1dfdc4a 100644 --- a/components/bt/bluedroid/bta/include/bta/bta_api.h +++ b/components/bt/bluedroid/bta/include/bta/bta_api.h @@ -769,6 +769,7 @@ typedef struct { tBLE_ADDR_TYPE addr_type; /* Peer device address type */ tBT_DEVICE_TYPE dev_type; UINT8 auth_mode; + BOOLEAN sc_support; /* Denotes if peer device supported secure connection while bonding. */ } tBTA_DM_AUTH_CMPL; @@ -784,6 +785,7 @@ typedef struct { /* Structure associated with BTA_DM_LINK_UP_EVT */ typedef struct { + BOOLEAN sc_downgrade; /* Security downgrade state. */ BD_ADDR bd_addr; /* BD address peer device. */ #if BLE_INCLUDED == TRUE tBTA_TRANSPORT link_type; @@ -1684,7 +1686,8 @@ extern void BTA_DmPasskeyReqReply(BOOLEAN accept, BD_ADDR bd_addr, UINT32 passke extern void BTA_DmAddDevice(BD_ADDR bd_addr, DEV_CLASS dev_class, LINK_KEY link_key, tBTA_SERVICE_MASK trusted_mask, BOOLEAN is_trusted, UINT8 key_type, - tBTA_IO_CAP io_cap, UINT8 pin_length); + tBTA_IO_CAP io_cap, UINT8 pin_length, + UINT8 sc_support); /******************************************************************************* ** diff --git a/components/bt/bluedroid/btc/core/btc_dm.c b/components/bt/bluedroid/btc/core/btc_dm.c index fbf153b5e..5434189ee 100644 --- a/components/bt/bluedroid/btc/core/btc_dm.c +++ b/components/bt/bluedroid/btc/core/btc_dm.c @@ -299,6 +299,27 @@ static void btc_dm_ble_auth_cmpl_evt (tBTA_DM_AUTH_CMPL *p_auth_cmpl) } #endif ///SMP_INCLUDED == TRUE +static void btc_dm_link_up_evt(tBTA_DM_LINK_UP *p_link_up) +{ + BD_ADDR bd_addr; + bt_bdaddr_t bt_bdaddr; + + memcpy(bd_addr, p_link_up->bd_addr, sizeof(BD_ADDR)); + memcpy(bt_bdaddr.address, p_link_up->bd_addr, sizeof(BD_ADDR)); + + if (p_link_up->sc_downgrade == 1) { + if (btc_storage_remove_bonded_device(&bt_bdaddr) == BT_STATUS_SUCCESS) { + if (BTA_DmRemoveDevice(bd_addr, BT_TRANSPORT_BR_EDR) == BTA_SUCCESS) { + BTC_TRACE_EVENT(" %s() Bonding information removed.", __FUNCTION__); + } else { + BTC_TRACE_ERROR(" %s() BTA_DmRemoveDevice error", __FUNCTION__); + } + } else { + BTC_TRACE_ERROR(" %s() btc_storage_remove_bonded_device error", __FUNCTION__); + } + } +} + static void btc_dm_auth_cmpl_evt (tBTA_DM_AUTH_CMPL *p_auth_cmpl) { /* Save link key, if not temporary */ @@ -322,7 +343,7 @@ static void btc_dm_auth_cmpl_evt (tBTA_DM_AUTH_CMPL *p_auth_cmpl) __FUNCTION__, p_auth_cmpl->key_type); ret = btc_storage_add_bonded_device(&bd_addr, p_auth_cmpl->key, p_auth_cmpl->key_type, - 16); + 16, p_auth_cmpl->sc_support); BTC_ASSERTC(ret == BT_STATUS_SUCCESS, "storing link key failed", ret); } else { BTC_TRACE_DEBUG("%s: Temporary key. Not storing. key_type=0x%x", @@ -665,6 +686,7 @@ void btc_dm_sec_cb_handler(btc_msg_t *msg) } #endif /* BTC_GAP_BT_INCLUDED == TRUE */ case BTA_DM_LINK_UP_EVT: + btc_dm_link_up_evt(&p_data->link_up); case BTA_DM_LINK_DOWN_EVT: case BTA_DM_HW_ERROR_EVT: BTC_TRACE_DEBUG( "btc_dm_sec_cback : unhandled event (%d)\n", msg->act ); diff --git a/components/bt/bluedroid/btc/core/btc_storage.c b/components/bt/bluedroid/btc/core/btc_storage.c index 654a1bf28..f7ffba015 100644 --- a/components/bt/bluedroid/btc/core/btc_storage.c +++ b/components/bt/bluedroid/btc/core/btc_storage.c @@ -37,7 +37,8 @@ bt_status_t btc_storage_add_bonded_device(bt_bdaddr_t *remote_bd_addr, LINK_KEY link_key, uint8_t key_type, - uint8_t pin_length) + uint8_t pin_length, + BOOLEAN sc_support) { bdstr_t bdstr; @@ -48,6 +49,7 @@ bt_status_t btc_storage_add_bonded_device(bt_bdaddr_t *remote_bd_addr, int ret = btc_config_set_int(bdstr, BTC_STORAGE_LINK_KEY_TYPE_STR, (int)key_type); ret &= btc_config_set_int(bdstr, BTC_STORAGE_PIN_LENGTH_STR, (int)pin_length); ret &= btc_config_set_bin(bdstr, BTC_STORAGE_LINK_KEY_STR, link_key, sizeof(LINK_KEY)); + ret &= btc_config_set_bin(bdstr, BTC_STORAGE_SC_SUPPORT, (uint8_t *)&sc_support, sizeof(sc_support)); /* write bonded info immediately */ btc_config_flush(); btc_config_unlock(); @@ -69,6 +71,7 @@ bt_status_t btc_storage_add_bonded_device(bt_bdaddr_t *remote_bd_addr, static bt_status_t btc_in_fetch_bonded_devices(int add) { BOOLEAN bt_linkkey_file_found = FALSE; + UINT8 sc_support = 0; btc_config_lock(); for (const btc_config_section_iter_t *iter = btc_config_section_begin(); iter != btc_config_section_end(); iter = btc_config_section_next(iter)) { @@ -93,9 +96,11 @@ static bt_status_t btc_in_fetch_bonded_devices(int add) uint2devclass((UINT32)cod, dev_class); } btc_config_get_int(name, BTC_STORAGE_PIN_LENGTH_STR, &pin_length); + size = sizeof(sc_support); + btc_config_get_bin(name, BTC_STORAGE_SC_SUPPORT, &sc_support, &size); #if (SMP_INCLUDED == TRUE) BTA_DmAddDevice(bd_addr.address, dev_class, link_key, 0, 0, - (UINT8)linkkey_type, 0, pin_length); + (UINT8)linkkey_type, 0, pin_length, (UINT8)sc_support); #endif ///SMP_INCLUDED == TRUE } bt_linkkey_file_found = TRUE; @@ -160,6 +165,9 @@ bt_status_t btc_storage_remove_bonded_device(bt_bdaddr_t *remote_bd_addr) if (btc_config_exist(bdstr, BTC_STORAGE_LINK_KEY_STR)) { ret &= btc_config_remove(bdstr, BTC_STORAGE_LINK_KEY_STR); } + if (btc_config_exist(bdstr, BTC_STORAGE_SC_SUPPORT)) { + ret &= btc_config_remove(bdstr, BTC_STORAGE_SC_SUPPORT); + } /* write bonded info immediately */ btc_config_flush(); btc_config_unlock(); @@ -187,6 +195,7 @@ int btc_storage_get_num_bt_bond_devices(void) if (string_is_bdaddr(name) && btc_config_exist(name, BTC_STORAGE_LINK_KEY_TYPE_STR) && btc_config_exist(name, BTC_STORAGE_PIN_LENGTH_STR) && + btc_config_exist(name, BTC_STORAGE_SC_SUPPORT) && btc_config_exist(name, BTC_STORAGE_LINK_KEY_STR)) { num_dev++; } @@ -223,6 +232,7 @@ bt_status_t btc_storage_get_bonded_bt_devices_list(bt_bdaddr_t *bond_dev, int de if (string_is_bdaddr(name) && btc_config_exist(name, BTC_STORAGE_LINK_KEY_TYPE_STR) && btc_config_exist(name, BTC_STORAGE_PIN_LENGTH_STR) && + btc_config_exist(name, BTC_STORAGE_SC_SUPPORT) && btc_config_exist(name, BTC_STORAGE_LINK_KEY_STR)) { string_to_bdaddr(name, &bd_addr); memcpy(bond_dev, &bd_addr, sizeof(bt_bdaddr_t)); @@ -232,4 +242,4 @@ bt_status_t btc_storage_get_bonded_bt_devices_list(bt_bdaddr_t *bond_dev, int de btc_config_unlock(); return BT_STATUS_SUCCESS; -} \ No newline at end of file +} diff --git a/components/bt/bluedroid/btc/include/btc/btc_storage.h b/components/bt/bluedroid/btc/include/btc/btc_storage.h index f40b169d4..9016502bd 100644 --- a/components/bt/bluedroid/btc/include/btc/btc_storage.h +++ b/components/bt/bluedroid/btc/include/btc/btc_storage.h @@ -25,6 +25,7 @@ #define BTC_STORAGE_LINK_KEY_STR "LinkKey" /* same as the ble */ #define BTC_STORAGE_LINK_KEY_TYPE_STR "LinkKeyType" #define BTC_STORAGE_PIN_LENGTH_STR "PinLength" +#define BTC_STORAGE_SC_SUPPORT "SCSupport" /******************************************************************************* ** @@ -40,7 +41,8 @@ bt_status_t btc_storage_add_bonded_device(bt_bdaddr_t *remote_bd_addr, LINK_KEY link_key, uint8_t key_type, - uint8_t pin_length); + uint8_t pin_length, + BOOLEAN sc_support); /******************************************************************************* ** diff --git a/components/bt/bluedroid/stack/btm/btm_acl.c b/components/bt/bluedroid/stack/btm/btm_acl.c index 8129e903a..63bf5f324 100644 --- a/components/bt/bluedroid/stack/btm/btm_acl.c +++ b/components/bt/bluedroid/stack/btm/btm_acl.c @@ -231,7 +231,7 @@ void btm_acl_created (BD_ADDR bda, DEV_CLASS dc, BD_NAME bdn, UINT8 xx; BTM_TRACE_DEBUG ("btm_acl_created hci_handle=%d link_role=%d transport=%d\n", - hci_handle, link_role, transport); + hci_handle, link_role, transport); /* Ensure we don't have duplicates */ p = btm_bda_to_acl(bda, transport); if (p != (tACL_CONN *)NULL) { @@ -241,7 +241,7 @@ void btm_acl_created (BD_ADDR bda, DEV_CLASS dc, BD_NAME bdn, p->transport = transport; #endif BTM_TRACE_DEBUG ("Duplicate btm_acl_created: RemBdAddr: %02x%02x%02x%02x%02x%02x\n", - bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]); + bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]); BTM_SetLinkPolicy(p->remote_addr, &btm_cb.btm_def_link_policy); return; } @@ -269,13 +269,16 @@ void btm_acl_created (BD_ADDR bda, DEV_CLASS dc, BD_NAME bdn, p->conn_addr_type = BLE_ADDR_PUBLIC; memcpy(p->conn_addr, &controller_get_interface()->get_address()->address, BD_ADDR_LEN); BTM_TRACE_DEBUG ("conn_addr: RemBdAddr: %02x%02x%02x%02x%02x%02x\n", - p->conn_addr[0], p->conn_addr[1], p->conn_addr[2], p->conn_addr[3], p->conn_addr[4], p->conn_addr[5]); + p->conn_addr[0], p->conn_addr[1], p->conn_addr[2], p->conn_addr[3], p->conn_addr[4], p->conn_addr[5]); #endif #endif p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE; btm_pm_sm_alloc(xx); +#if (CLASSIC_BT_INCLUDED == TRUE) + btm_sec_update_legacy_auth_state(p, BTM_ACL_LEGACY_AUTH_NONE); +#endif if (dc) { memcpy (p->remote_dc, dc, DEV_CLASS_LEN); @@ -299,28 +302,34 @@ void btm_acl_created (BD_ADDR bda, DEV_CLASS dc, BD_NAME bdn, #endif if (p_dev_rec && !(transport == BT_TRANSPORT_LE)) { - /* If remote features already known, copy them and continue connection setup */ - if ((p_dev_rec->num_read_pages) && - (p_dev_rec->num_read_pages <= (HCI_EXT_FEATURES_PAGE_MAX + 1))) { - memcpy (p->peer_lmp_features, p_dev_rec->features, - (HCI_FEATURE_BYTES_PER_PAGE * p_dev_rec->num_read_pages)); - p->num_read_pages = p_dev_rec->num_read_pages; + if (!p_dev_rec->remote_secure_connection_previous_state) { + /* If remote features already known, copy them and continue connection setup */ + if ((p_dev_rec->num_read_pages) && + (p_dev_rec->num_read_pages <= (HCI_EXT_FEATURES_PAGE_MAX + 1))) { + memcpy (p->peer_lmp_features, p_dev_rec->features, + (HCI_FEATURE_BYTES_PER_PAGE * p_dev_rec->num_read_pages)); + p->num_read_pages = p_dev_rec->num_read_pages; #if (CLASSIC_BT_INCLUDED == TRUE) - const UINT8 req_pend = (p_dev_rec->sm4 & BTM_SM4_REQ_PEND); + const UINT8 req_pend = (p_dev_rec->sm4 & BTM_SM4_REQ_PEND); #endif ///CLASSIC_BT_INCLUDED == TRUE - /* Store the Peer Security Capabilites (in SM4 and rmt_sec_caps) */ + /* Store the Peer Security Capabilites (in SM4 and rmt_sec_caps) */ #if (SMP_INCLUDED == TRUE) - btm_sec_set_peer_sec_caps(p, p_dev_rec); + btm_sec_set_peer_sec_caps(p, p_dev_rec); #endif ///SMP_INCLUDED == TRUE #if (CLASSIC_BT_INCLUDED == TRUE) - BTM_TRACE_API("%s: pend:%d\n", __FUNCTION__, req_pend); - if (req_pend) { - /* Request for remaining Security Features (if any) */ - l2cu_resubmit_pending_sec_req (p_dev_rec->bd_addr); - } + BTM_TRACE_API("%s: pend:%d\n", __FUNCTION__, req_pend); + if (req_pend) { + /* Request for remaining Security Features (if any) */ + l2cu_resubmit_pending_sec_req (p_dev_rec->bd_addr); + } #endif ///CLASSIC_BT_INCLUDED == TRUE - btm_establish_continue (p); - return; + btm_establish_continue (p); + return; + } + } else { + /* If remote features indicated secure connection (SC) mode, check the remote feautres again*/ + /* this is to prevent from BIAS attack where attacker can downgrade SC mode*/ + btm_read_remote_features (p->hci_handle); } } @@ -329,13 +338,13 @@ void btm_acl_created (BD_ADDR bda, DEV_CLASS dc, BD_NAME bdn, if (p_dev_rec && transport == BT_TRANSPORT_LE) { #if BLE_PRIVACY_SPT == TRUE btm_ble_get_acl_remote_addr (p_dev_rec, p->active_remote_addr, - &p->active_remote_addr_type); + &p->active_remote_addr_type); #endif if (link_role == HCI_ROLE_MASTER) { btsnd_hcic_ble_read_remote_feat(p->hci_handle); } else if (HCI_LE_SLAVE_INIT_FEAT_EXC_SUPPORTED(controller_get_interface()->get_features_ble()->as_array) - && link_role == HCI_ROLE_SLAVE) { + && link_role == HCI_ROLE_SLAVE) { btsnd_hcic_rmt_ver_req (p->hci_handle); } else { btm_establish_continue(p); @@ -791,6 +800,22 @@ void btm_acl_encrypt_change (UINT16 handle, UINT8 status, UINT8 encr_enable) } #endif } +#if (CLASSIC_BT_INCLUDED == TRUE) + /* If authentication is done through legacy authentication and esp32 has + * not authenticated peer deivce yet, do not proceed for encrytion and + * first authenticate it. */ + else if ((BTM_BothEndsSupportSecureConnections(p->remote_addr) == 0) && + ((p->legacy_auth_state & BTM_ACL_LEGACY_AUTH_SELF) == 0)) { + if ((p_dev_rec = btm_find_dev (p->remote_addr)) != NULL) { + if (btm_sec_legacy_authentication_mutual(p_dev_rec)) { + btm_sec_update_legacy_auth_state(btm_bda_to_acl(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR), BTM_ACL_LEGACY_AUTH_SELF); + } else { + BTM_TRACE_ERROR("%s failed, Resources not available for Authentication procedure", __FUNCTION__); + } + } + } +#endif + } /******************************************************************************* ** @@ -1212,6 +1237,7 @@ void btm_establish_continue (tACL_CONN *p_acl_cb) evt_data.conn.p_bdn = p_acl_cb->remote_name; evt_data.conn.p_dc = p_acl_cb->remote_dc; evt_data.conn.p_features = p_acl_cb->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0]; + evt_data.conn.sc_downgrade = p_acl_cb->sc_downgrade; #if BLE_INCLUDED == TRUE evt_data.conn.handle = p_acl_cb->hci_handle; evt_data.conn.transport = p_acl_cb->transport; diff --git a/components/bt/bluedroid/stack/btm/btm_dev.c b/components/bt/bluedroid/stack/btm/btm_dev.c index 2e877a85e..95a2e27ff 100644 --- a/components/bt/bluedroid/stack/btm/btm_dev.c +++ b/components/bt/bluedroid/stack/btm/btm_dev.c @@ -60,7 +60,7 @@ static tBTM_SEC_DEV_REC *btm_find_oldest_dev (void); BOOLEAN BTM_SecAddDevice (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name, UINT8 *features, UINT32 trusted_mask[], LINK_KEY link_key, UINT8 key_type, tBTM_IO_CAP io_cap, - UINT8 pin_length) + UINT8 pin_length, UINT8 sc_support) { #if (SMP_INCLUDED == TRUE) tBTM_SEC_DEV_REC *p_dev_rec; @@ -98,6 +98,7 @@ BOOLEAN BTM_SecAddDevice (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name, p_dev_rec->bond_type = BOND_TYPE_UNKNOWN; /* Default value */ p_dev_rec->timestamp = btm_cb.dev_rec_count++; + p_dev_rec->remote_secure_connection_previous_state = sc_support; if (dev_class) { memcpy (p_dev_rec->dev_class, dev_class, DEV_CLASS_LEN); diff --git a/components/bt/bluedroid/stack/btm/btm_devctl.c b/components/bt/bluedroid/stack/btm/btm_devctl.c index f34165b3b..f7b32ce87 100644 --- a/components/bt/bluedroid/stack/btm/btm_devctl.c +++ b/components/bt/bluedroid/stack/btm/btm_devctl.c @@ -790,13 +790,24 @@ void btm_vendor_specific_evt (UINT8 *p, UINT8 evt_len) { UINT8 i; - BTM_TRACE_DEBUG ("BTM Event: Vendor Specific event from controller"); +#if (CLASSIC_BT_INCLUDED == TRUE) + UINT8 sub_event; + UINT8 *p_evt = p; + STREAM_TO_UINT8(sub_event, p_evt); + /* Check in subevent if authentication is through Legacy Authentication. */ + if (sub_event == ESP_VS_REM_LEGACY_AUTH_CMP) { + UINT16 hci_handle; + STREAM_TO_UINT16(hci_handle, p_evt); + btm_sec_handle_remote_legacy_auth_cmp(hci_handle); + } +#endif /// (CLASSIC_BT_INCLUDED == TRUE) for (i = 0; i < BTM_MAX_VSE_CALLBACKS; i++) { if (btm_cb.devcb.p_vend_spec_cb[i]) { (*btm_cb.devcb.p_vend_spec_cb[i])(evt_len, p); } } + BTM_TRACE_DEBUG ("BTM Event: Vendor Specific event from controller"); } diff --git a/components/bt/bluedroid/stack/btm/btm_sec.c b/components/bt/bluedroid/stack/btm/btm_sec.c index 877d3d6d2..47983f825 100644 --- a/components/bt/bluedroid/stack/btm/btm_sec.c +++ b/components/bt/bluedroid/stack/btm/btm_sec.c @@ -3917,10 +3917,11 @@ void btm_sec_auth_complete (UINT16 handle, UINT8 status) (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED))) { status = HCI_SUCCESS; } + /* Currently we do not notify user if it is a keyboard which connects */ - /* User probably Disabled the keyboard while it was asleap. Let her try */ + /* User probably Disabled the keyboard while it was asleep. Let her try */ if (btm_cb.api.p_auth_complete_callback) { - /* report the suthentication status */ + /* report the authentication status */ if (old_state != BTM_PAIR_STATE_IDLE) { (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class, @@ -3930,6 +3931,9 @@ void btm_sec_auth_complete (UINT16 handle, UINT8 status) p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; +#if (CLASSIC_BT_INCLUDED == TRUE) + btm_sec_update_legacy_auth_state(btm_bda_to_acl(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR), BTM_ACL_LEGACY_AUTH_SELF); +#endif /* If this is a bonding procedure can disconnect the link now */ if (are_bonding) { p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE; @@ -4657,12 +4661,24 @@ void btm_sec_link_key_notification (UINT8 *p_bda, UINT8 *p_link_key, UINT8 key_t /* If connection was made to do bonding restore link security if changed */ btm_restore_mode(); + /* Store the previous state of secure connection as current state. Since + * this is the first encounter with the remote device, whatever the remote + * device's SC state is, it cannot lower the SC level from this. */ + p_dev_rec->remote_secure_connection_previous_state = p_dev_rec->remote_supports_secure_connections; + if (p_dev_rec->remote_supports_secure_connections) { + BTM_TRACE_EVENT ("Remote device supports Secure Connection"); + } else { + BTM_TRACE_EVENT ("Remote device does not support Secure Connection"); + } if (key_type != BTM_LKEY_TYPE_CHANGED_COMB) { p_dev_rec->link_key_type = key_type; } p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_KNOWN; +#if (CLASSIC_BT_INCLUDED == TRUE) + btm_sec_update_legacy_auth_state(btm_bda_to_acl(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR), BTM_ACL_LEGACY_AUTH_NONE); +#endif /* * Until this point in time, we do not know if MITM was enabled, hence we * add the extended security flag here. @@ -4695,7 +4711,8 @@ void btm_sec_link_key_notification (UINT8 *p_bda, UINT8 *p_link_key, UINT8 key_t __FUNCTION__, p_dev_rec->link_key_type); (*btm_cb.api.p_link_key_callback) (p_bda, p_dev_rec->dev_class, p_dev_rec->sec_bd_name, - p_link_key, p_dev_rec->link_key_type); + p_link_key, p_dev_rec->link_key_type, + p_dev_rec->remote_supports_secure_connections); } } else { if ((p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB_P_256) || @@ -4752,7 +4769,8 @@ void btm_sec_link_key_notification (UINT8 *p_bda, UINT8 *p_link_key, UINT8 key_t } else { (*btm_cb.api.p_link_key_callback) (p_bda, p_dev_rec->dev_class, p_dev_rec->sec_bd_name, - p_link_key, p_dev_rec->link_key_type); + p_link_key, p_dev_rec->link_key_type, + p_dev_rec->remote_supports_secure_connections); } } } @@ -5543,7 +5561,9 @@ static void btm_send_link_key_notif (tBTM_SEC_DEV_REC *p_dev_rec) if (btm_cb.api.p_link_key_callback) { (*btm_cb.api.p_link_key_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class, p_dev_rec->sec_bd_name, p_dev_rec->link_key, - p_dev_rec->link_key_type); + p_dev_rec->link_key_type, + p_dev_rec->remote_supports_secure_connections); + } } #endif ///SMP_INCLUDED == TRUE @@ -5894,6 +5914,29 @@ void btm_sec_set_peer_sec_caps(tACL_CONN *p_acl_cb, tBTM_SEC_DEV_REC *p_dev_rec) BTM_TRACE_API("%s: sm4: 0x%02x, rmt_support_for_secure_connections %d\n", __FUNCTION__, p_dev_rec->sm4, p_dev_rec->remote_supports_secure_connections); + /* Store previous state of remote device to check if peer device downgraded + * it's secure connection state. */ +#if (CLASSIC_BT_INCLUDED == TRUE) + if (p_dev_rec->remote_supports_secure_connections >= p_dev_rec->remote_secure_connection_previous_state) { + p_dev_rec->remote_secure_connection_previous_state = p_dev_rec->remote_supports_secure_connections; + } else { + BTM_TRACE_ERROR("Remote Device downgraded security from SC, deleting Link Key"); + + /* Mark in ACL packet that secure connection is downgraded. */ + p_acl_cb->sc_downgrade = 1; + p_dev_rec->remote_secure_connection_previous_state = 0; + + /* As peer device downgraded it's security, peer device is a suspicious + * device. Hence remove pairing information by removing link key + * information. */ + memset(p_dev_rec->link_key, 0, LINK_KEY_LEN); + p_dev_rec->sec_flags &= ~(BTM_SEC_AUTHORIZED | BTM_SEC_AUTHENTICATED + | BTM_SEC_ENCRYPTED | BTM_SEC_NAME_KNOWN + | BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED + | BTM_SEC_ROLE_SWITCHED | BTM_SEC_16_DIGIT_PIN_AUTHED); + return; + } +#endif if (p_dev_rec->remote_features_needed) { BTM_TRACE_EVENT("%s: Now device in SC Only mode, waiting for peer remote features!\n", @@ -6156,5 +6199,62 @@ static BOOLEAN btm_sec_is_master(tBTM_SEC_DEV_REC *p_dev_rec) tACL_CONN *p = btm_bda_to_acl(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR); return (p && (p->link_role == BTM_ROLE_MASTER)); } -#endif ///SMP_INCLUDED == TRUE +#if (CLASSIC_BT_INCLUDED == TRUE) +/******************************************************************************* +** +** Function btm_sec_legacy_authentication_mutual +** +** Description This function is called when legacy authentication is used +** and only remote device has completed the authentication +** +** Returns TRUE if aunthentication command sent successfully +** +*******************************************************************************/ +BOOLEAN btm_sec_legacy_authentication_mutual (tBTM_SEC_DEV_REC *p_dev_rec) +{ + return (btm_sec_start_authentication (p_dev_rec)); +} + +/******************************************************************************* +** +** Function btm_sec_update_legacy_auth_state +** +** Description This function updates the legacy authentication state +** +** Returns void +** +*******************************************************************************/ +void btm_sec_update_legacy_auth_state(tACL_CONN *p_acl_cb, UINT8 legacy_auth_state) +{ + if (p_acl_cb) { + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (p_acl_cb->hci_handle); + if (p_dev_rec) { + if ((BTM_BothEndsSupportSecureConnections(p_dev_rec->bd_addr) == 0) && + (legacy_auth_state != BTM_ACL_LEGACY_AUTH_NONE)) { + p_acl_cb->legacy_auth_state |= legacy_auth_state; + } else { + p_acl_cb->legacy_auth_state = BTM_ACL_LEGACY_AUTH_NONE; + } + } + } +} + +/******************************************************************************* +** +** Function btm_sec_handle_remote_legacy_auth_cmp +** +** Description This function updates the legacy authneticaiton state +** to indicate that remote device has completed the authentication +** +** Returns void +** +*******************************************************************************/ +void btm_sec_handle_remote_legacy_auth_cmp(UINT16 handle) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle); + tACL_CONN *p_acl_cb = btm_bda_to_acl(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR); + btm_sec_update_legacy_auth_state(p_acl_cb, BTM_ACL_LEGACY_AUTH_REMOTE); +} +#endif /// (CLASSIC_BT_INCLUDED == TRUE) +#endif ///SMP_INCLUDED == TRUE diff --git a/components/bt/bluedroid/stack/btm/include/btm_int.h b/components/bt/bluedroid/stack/btm/include/btm_int.h index 99f5bc7a8..fb42a9987 100644 --- a/components/bt/bluedroid/stack/btm/include/btm_int.h +++ b/components/bt/bluedroid/stack/btm/include/btm_int.h @@ -40,6 +40,8 @@ #endif #endif +#define ESP_VS_REM_LEGACY_AUTH_CMP 0x03 + #if BTM_MAX_LOC_BD_NAME_LEN > 0 typedef char tBTM_LOC_BD_NAME[BTM_MAX_LOC_BD_NAME_LEN + 1]; #endif @@ -92,6 +94,13 @@ UINT8 lmp_version; BOOLEAN in_use; UINT8 link_role; BOOLEAN link_up_issued; /* True if busy_level link up has been issued */ +BOOLEAN sc_downgrade; /* Store if security is downgraded or not. */ + +#define BTM_ACL_LEGACY_AUTH_NONE (0) +#define BTM_ACL_LEGACY_AUTH_SELF (1<<0) +#define BTM_ACL_LEGACY_AUTH_REMOTE (1<<1) +#define BTM_ACL_LEGACY_AUTH_MUTUAL (1<<2) +UINT8 legacy_auth_state; #define BTM_ACL_SWKEY_STATE_IDLE 0 #define BTM_ACL_SWKEY_STATE_MODE_CHANGE 1 @@ -592,6 +601,8 @@ typedef struct { /* "Secure Connections Only" mode and it receives */ /* HCI_IO_CAPABILITY_REQUEST_EVT from the peer before */ /* it knows peer's support for Secure Connections */ + BOOLEAN remote_secure_connection_previous_state; /* Stores if peer ever supported + secure connection. This will be helpful to know when peer device downgrades it's security. */ UINT16 ble_hci_handle; /* use in DUMO connection */ UINT8 enc_key_size; /* current link encryption key size */ @@ -1146,6 +1157,10 @@ void btm_sem_free(void); void btm_lock_free(void); +void btm_sec_handle_remote_legacy_auth_cmp(UINT16 handle); +void btm_sec_update_legacy_auth_state(tACL_CONN *p_acl_cb, UINT8 legacy_auth_state); +BOOLEAN btm_sec_legacy_authentication_mutual (tBTM_SEC_DEV_REC *p_dev_rec); + /* #ifdef __cplusplus } diff --git a/components/bt/bluedroid/stack/include/stack/btm_api.h b/components/bt/bluedroid/stack/include/stack/btm_api.h index a997e6fa5..754a2b945 100644 --- a/components/bt/bluedroid/stack/include/stack/btm_api.h +++ b/components/bt/bluedroid/stack/include/stack/btm_api.h @@ -825,14 +825,15 @@ typedef UINT16 tBTM_BL_EVENT_MASK; /* the data type associated with BTM_BL_CONN_EVT */ typedef struct { - tBTM_BL_EVENT event; /* The event reported. */ - BD_ADDR_PTR p_bda; /* The address of the newly connected device */ - DEV_CLASS_PTR p_dc; /* The device class */ - BD_NAME_PTR p_bdn; /* The device name */ - UINT8 *p_features; /* pointer to the remote device's features page[0] (supported features page) */ + tBTM_BL_EVENT event; /* The event reported. */ + BD_ADDR_PTR p_bda; /* The address of the newly connected device */ + DEV_CLASS_PTR p_dc; /* The device class */ + BD_NAME_PTR p_bdn; /* The device name */ + UINT8 *p_features; /* pointer to the remote device's features page[0] (supported features page) */ + BOOLEAN sc_downgrade; /* Secure connection downgrade state. */ #if BLE_INCLUDED == TRUE - UINT16 handle; /* connection handle */ - tBT_TRANSPORT transport; /* link is LE or not */ + UINT16 handle; /* connection handle */ + tBT_TRANSPORT transport; /* link is LE or not */ #endif } tBTM_BL_CONN_DATA; @@ -1352,7 +1353,7 @@ typedef UINT8 (tBTM_PIN_CALLBACK) (BD_ADDR bd_addr, DEV_CLASS dev_class, */ typedef UINT8 (tBTM_LINK_KEY_CALLBACK) (BD_ADDR bd_addr, DEV_CLASS dev_class, tBTM_BD_NAME bd_name, UINT8 *key, - UINT8 key_type); + UINT8 key_type, BOOLEAN sc_support); /* Remote Name Resolved. Parameters are @@ -3406,7 +3407,8 @@ UINT8 BTM_SecClrService (UINT8 service_id); BOOLEAN BTM_SecAddDevice (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name, UINT8 *features, UINT32 trusted_mask[], LINK_KEY link_key, - UINT8 key_type, tBTM_IO_CAP io_cap, UINT8 pin_length); + UINT8 key_type, tBTM_IO_CAP io_cap, UINT8 pin_length, + UINT8 sc_support); /******************************************************************************* diff --git a/components/bt/include/esp_bt.h b/components/bt/include/esp_bt.h index acf346aab..fb38fe68d 100644 --- a/components/bt/include/esp_bt.h +++ b/components/bt/include/esp_bt.h @@ -25,7 +25,7 @@ extern "C" { #endif -#define ESP_BT_CONTROLLER_CONFIG_MAGIC_VAL 0x20200106 +#define ESP_BT_CONTROLLER_CONFIG_MAGIC_VAL 0x20200611 /** * @brief Bluetooth mode for controller enable/disable @@ -102,6 +102,12 @@ the adv packet will be discarded until the memory is restored. */ #define BTDM_CTRL_AUTO_LATENCY_EFF false #endif +#ifdef CONFIG_BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT_EFF +#define BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT_EFF CONFIG_BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT_EFF +#else +#define BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT_EFF false +#endif + #define BTDM_CONTROLLER_BLE_MAX_CONN_LIMIT 9 //Maximum BLE connection limitation #define BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN_LIMIT 7 //Maximum ACL connection limitation #define BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_LIMIT 3 //Maximum SCO/eSCO connection limitation @@ -115,7 +121,7 @@ the adv packet will be discarded until the memory is restored. */ .hci_uart_no = BT_HCI_UART_NO_DEFAULT, \ .hci_uart_baudrate = BT_HCI_UART_BAUDRATE_DEFAULT, \ .scan_duplicate_mode = SCAN_DUPLICATE_MODE, \ - .scan_duplicate_type = SCAN_DUPLICATE_TYPE_VALUE, \ + .scan_duplicate_type = SCAN_DUPLICATE_TYPE_VALUE, \ .normal_adv_size = NORMAL_SCAN_DUPLICATE_CACHE_SIZE, \ .mesh_adv_size = MESH_DUPLICATE_SCAN_CACHE_SIZE, \ .send_adv_reserved_size = SCAN_SEND_ADV_RESERVED_SIZE, \ @@ -125,6 +131,7 @@ the adv packet will be discarded until the memory is restored. */ .bt_max_acl_conn = CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN_EFF, \ .bt_sco_datapath = CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_EFF, \ .auto_latency = BTDM_CTRL_AUTO_LATENCY_EFF, \ + .bt_legacy_auth_vs_evt = BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT_EFF, \ .bt_max_sync_conn = CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_EFF, \ .magic = ESP_BT_CONTROLLER_CONFIG_MAGIC_VAL, \ }; @@ -157,6 +164,7 @@ typedef struct { uint8_t bt_max_acl_conn; /*!< BR/EDR maximum ACL connection numbers */ uint8_t bt_sco_datapath; /*!< SCO data path, i.e. HCI or PCM module */ bool auto_latency; /*!< BLE auto latency, used to enhance classic BT performance */ + bool bt_legacy_auth_vs_evt; /*!< BR/EDR Legacy auth complete event required to protect from BIAS attack */ /* * Following parameters can not be configured runtime when call esp_bt_controller_init() * It will be overwrite with a constant value which in menuconfig or from a macro. diff --git a/components/bt/lib b/components/bt/lib index 63e7a37c6..1f1002a2c 160000 --- a/components/bt/lib +++ b/components/bt/lib @@ -1 +1 @@ -Subproject commit 63e7a37c6c6c5647ed09ff5196c0b76ebd98de16 +Subproject commit 1f1002a2c4589d1873fa41c49cb616208082cdb9