Răsfoiți Sursa

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.

Signed-off-by: Chinmay Chhajed <chinmay.chhajed@espressif.com>
Chinmay Chhajed 5 ani în urmă
părinte
comite
a9d4ed4a55

+ 13 - 0
components/bt/Kconfig

@@ -90,6 +90,19 @@ menu "Bluetooth"
             default BTDM_CTRL_AUTO_LATENCY if BTDM_CTRL_MODE_BTDM
             default n
 
+        config BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT
+            bool "Legacy Authentication Vendor Specific Event Enable"
+            depends on BTDM_CTRL_MODE_BR_EDR_ONLY || BTDM_CTRL_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
+            int
+            default BTDM_CTRL_BR_EDR_MAX_ACL_CONN if BTDM_CTRL_MODE_BR_EDR_ONLY || BTDM_CTRL_MODE_BTDM
+            default 0
+
 
         config BTDM_CTRL_BLE_MAX_CONN_EFF
             int

+ 1 - 1
components/bt/controller/lib

@@ -1 +1 @@
-Subproject commit 2575a67bc744a617b2e10267174f5b642d890c37
+Subproject commit 5c06e49df86b799d99fea4e3fd6205266c0499c6

+ 7 - 3
components/bt/host/bluedroid/bta/dm/bta_dm_act.c

@@ -63,7 +63,7 @@ static UINT8 bta_dm_authorize_cback (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NA
 #if (CLASSIC_BT_INCLUDED == TRUE)
 static UINT8 bta_dm_pin_cback (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name, BOOLEAN min_16_digit);
 #endif /// CLASSIC_BT_INCLUDED == TRUE
-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);
@@ -950,7 +950,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]);
@@ -2920,7 +2920,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;
@@ -2942,6 +2943,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;
@@ -3219,6 +3221,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
@@ -3445,6 +3448,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 {

+ 3 - 1
components/bt/host/bluedroid/bta/dm/bta_dm_api.c

@@ -647,7 +647,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;
@@ -660,6 +661,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;

+ 2 - 0
components/bt/host/bluedroid/bta/dm/include/bta_dm_int.h

@@ -404,6 +404,7 @@ typedef struct {
     UINT8           new_role;
     BD_ADDR         bd_addr;
     UINT8           hci_status;
+    BOOLEAN         sc_downgrade;
 #if BLE_INCLUDED == TRUE
     UINT16          handle;
 #endif
@@ -445,6 +446,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 */

+ 4 - 1
components/bt/host/bluedroid/bta/include/bta/bta_api.h

@@ -780,6 +780,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;
 
 
@@ -795,6 +796,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;
@@ -1708,7 +1710,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);
 
 /*******************************************************************************
 **

+ 23 - 1
components/bt/host/bluedroid/btc/core/btc_dm.c

@@ -300,6 +300,27 @@ static void btc_dm_ble_auth_cmpl_evt (tBTA_DM_AUTH_CMPL *p_auth_cmpl)
 #endif  ///BLE_INCLUDED == TRUE
 #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 */
@@ -323,7 +344,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",
@@ -670,6 +691,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 );

+ 13 - 3
components/bt/host/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;
-}
+}

+ 3 - 1
components/bt/host/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);
 
 /*******************************************************************************
 **

+ 47 - 21
components/bt/host/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;

+ 2 - 1
components/bt/host/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);

+ 13 - 2
components/bt/host/bluedroid/stack/btm/btm_devctl.c

@@ -792,13 +792,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");
 }
 
 

+ 106 - 6
components/bt/host/bluedroid/stack/btm/btm_sec.c

@@ -3932,10 +3932,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,
@@ -3945,6 +3946,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;
@@ -4674,12 +4678,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.
@@ -4712,7 +4728,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) ||
@@ -4769,7 +4786,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);
             }
         }
     }
@@ -5562,7 +5580,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
@@ -5920,6 +5940,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",
@@ -6185,5 +6228,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

+ 15 - 0
components/bt/host/bluedroid/stack/btm/include/btm_int.h

@@ -41,6 +41,8 @@
 #include "stack/smp_api.h"
 #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
@@ -93,6 +95,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
@@ -596,6 +605,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 */
@@ -1155,6 +1166,10 @@ void btm_ble_sem_free(void);
 
 void btm_ble_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
 }

+ 11 - 9
components/bt/host/bluedroid/stack/include/stack/btm_api.h

@@ -828,14 +828,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;
 
@@ -1356,7 +1357,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
@@ -3410,7 +3411,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);
 
 
 /*******************************************************************************

+ 9 - 1
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
@@ -117,6 +117,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
@@ -140,6 +146,7 @@ the adv packet will be discarded until the memory is restored. */
     .bt_max_acl_conn = CONFIG_BTDM_CTRL_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_CTRL_BR_EDR_MAX_SYNC_CONN_EFF,         \
     .ble_sca = CONFIG_BTDM_BLE_SLEEP_CLOCK_ACCURACY_INDEX_EFF,             \
     .magic = ESP_BT_CONTROLLER_CONFIG_MAGIC_VAL,                           \
@@ -173,6 +180,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.