Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/bluetooth/hci.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
74 changes: 69 additions & 5 deletions subsys/bluetooth/host/hci_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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)
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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)) {
/*
Expand Down Expand Up @@ -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 */

Expand Down