diff --git a/include/bluetooth/hci.h b/include/bluetooth/hci.h index 64f8066cdda68..0460d42b3c7de 100644 --- a/include/bluetooth/hci.h +++ b/include/bluetooth/hci.h @@ -708,6 +708,9 @@ struct bt_hci_rp_read_rssi { s8_t rssi; } __packed; +#define BT_HCI_ENCRYPTION_KEY_SIZE_MIN 7 +#define BT_HCI_ENCRYPTION_KEY_SIZE_MAX 16 + #define BT_HCI_OP_READ_ENCRYPTION_KEY_SIZE BT_OP(BT_OGF_STATUS, 0x0008) struct bt_hci_cp_read_encryption_key_size { u16_t handle; diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index de812fd732f63..ef750f9686782 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -1838,11 +1838,55 @@ static void conn_req(struct net_buf *buf) bt_conn_unref(conn); } -static void update_sec_level_br(struct bt_conn *conn) +static bool br_sufficient_key_size(struct bt_conn *conn) +{ + struct bt_hci_cp_read_encryption_key_size *cp; + struct bt_hci_rp_read_encryption_key_size *rp; + struct net_buf *buf, *rsp; + u8_t key_size; + int err; + + buf = bt_hci_cmd_create(BT_HCI_OP_READ_ENCRYPTION_KEY_SIZE, + sizeof(*cp)); + if (!buf) { + BT_ERR("Failed to allocate command buffer"); + return false; + } + + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle = sys_cpu_to_le16(conn->handle); + + err = bt_hci_cmd_send_sync(BT_HCI_OP_READ_ENCRYPTION_KEY_SIZE, + buf, &rsp); + if (err) { + BT_ERR("Failed to read encryption key size (err %d)", err); + return false; + } + + if (rsp->len < sizeof(*rp)) { + BT_ERR("Too small command complete for encryption key size"); + net_buf_unref(rsp); + return false; + } + + rp = (void *)rsp->data; + key_size = rp->key_size; + net_buf_unref(rsp); + + BT_DBG("Encryption key size is %u", key_size); + + if (conn->sec_level == BT_SECURITY_FIPS) { + return key_size == BT_HCI_ENCRYPTION_KEY_SIZE_MAX; + } + + return key_size >= BT_HCI_ENCRYPTION_KEY_SIZE_MIN; +} + +static bool update_sec_level_br(struct bt_conn *conn) { if (!conn->encrypt) { conn->sec_level = BT_SECURITY_LOW; - return; + return true; } if (conn->br.link_key) { @@ -1860,10 +1904,19 @@ static void update_sec_level_br(struct bt_conn *conn) conn->sec_level = BT_SECURITY_MEDIUM; } + if (!br_sufficient_key_size(conn)) { + BT_ERR("Encryption key size is not sufficient"); + bt_conn_disconnect(conn, BT_HCI_ERR_AUTHENTICATION_FAIL); + return false; + } + if (conn->required_sec_level > conn->sec_level) { BT_ERR("Failed to set required security level"); bt_conn_disconnect(conn, BT_HCI_ERR_AUTHENTICATION_FAIL); + return false; } + + return true; } static void synchronous_conn_complete(struct net_buf *buf) @@ -1919,7 +1972,12 @@ static void conn_complete(struct net_buf *buf) conn->handle = handle; conn->err = 0U; conn->encrypt = evt->encr_enabled; - update_sec_level_br(conn); + + if (!update_sec_level_br(conn)) { + bt_conn_unref(conn); + return; + } + bt_conn_set_state(conn, BT_CONN_CONNECTED); bt_conn_unref(conn); @@ -3057,7 +3115,10 @@ static void hci_encrypt_change(struct net_buf *buf) #endif /* CONFIG_BT_SMP */ #if defined(CONFIG_BT_BREDR) if (conn->type == BT_CONN_TYPE_BR) { - update_sec_level_br(conn); + if (!update_sec_level_br(conn)) { + bt_conn_unref(conn); + return; + } if (IS_ENABLED(CONFIG_BT_SMP)) { /* @@ -3117,7 +3178,10 @@ static void hci_encrypt_key_refresh_complete(struct net_buf *buf) #endif /* CONFIG_BT_SMP */ #if defined(CONFIG_BT_BREDR) if (conn->type == BT_CONN_TYPE_BR) { - update_sec_level_br(conn); + if (!update_sec_level_br(conn)) { + bt_conn_unref(conn); + return; + } } #endif /* CONFIG_BT_BREDR */