Bluetooth: host: Set error in security changed when not required level

Set the error in the security changed callback when the encryption has
not reached the required security level.
Terminate the pairing procedure in SMP on failure to avoid the security
changed callback being called twice in this case.

Signed-off-by: Joakim Andersson <joakim.andersson@nordicsemi.no>
This commit is contained in:
Joakim Andersson 2021-02-09 09:19:10 +01:00 committed by Anas Nashif
commit 6b8fbfa68a
2 changed files with 46 additions and 23 deletions

View file

@ -3582,13 +3582,8 @@ done:
bt_adv_foreach(adv_unpause_enabled, NULL);
}
static void update_sec_level(struct bt_conn *conn)
static bool update_sec_level(struct bt_conn *conn)
{
if (!conn->encrypt) {
conn->sec_level = BT_SECURITY_L1;
return;
}
if (conn->le.keys && (conn->le.keys->flags & BT_KEYS_AUTHENTICATED)) {
if (conn->le.keys->flags & BT_KEYS_SC &&
conn->le.keys->enc_size == BT_SMP_MAX_ENC_KEY_SIZE) {
@ -3600,10 +3595,7 @@ static void update_sec_level(struct bt_conn *conn)
conn->sec_level = BT_SECURITY_L2;
}
if (conn->required_sec_level > conn->sec_level) {
BT_ERR("Failed to set required security level");
bt_conn_disconnect(conn, BT_HCI_ERR_AUTH_FAIL);
}
return !(conn->required_sec_level > conn->sec_level);
}
#endif /* CONFIG_BT_SMP */
@ -3612,6 +3604,7 @@ static void hci_encrypt_change(struct net_buf *buf)
{
struct bt_hci_evt_encrypt_change *evt = (void *)buf->data;
uint16_t handle = sys_le16_to_cpu(evt->handle);
uint8_t status = evt->status;
struct bt_conn *conn;
BT_DBG("status 0x%02x handle %u encrypt 0x%02x", evt->status, handle,
@ -3623,9 +3616,9 @@ static void hci_encrypt_change(struct net_buf *buf)
return;
}
if (evt->status) {
bt_conn_security_changed(conn, evt->status,
bt_security_err_get(evt->status));
if (status) {
bt_conn_security_changed(conn, status,
bt_security_err_get(status));
bt_conn_unref(conn);
return;
}
@ -3645,7 +3638,10 @@ static void hci_encrypt_change(struct net_buf *buf)
if (conn->encrypt) {
bt_smp_update_keys(conn);
}
update_sec_level(conn);
if (!update_sec_level(conn)) {
status = BT_HCI_ERR_AUTH_FAIL;
}
}
#endif /* CONFIG_BT_SMP */
#if defined(CONFIG_BT_BREDR)
@ -3668,7 +3664,12 @@ static void hci_encrypt_change(struct net_buf *buf)
}
#endif /* CONFIG_BT_BREDR */
bt_conn_security_changed(conn, evt->status, BT_SECURITY_ERR_SUCCESS);
bt_conn_security_changed(conn, status, bt_security_err_get(status));
if (status) {
BT_ERR("Failed to set required security level");
bt_conn_disconnect(conn, status);
}
bt_conn_unref(conn);
}
@ -3676,6 +3677,7 @@ static void hci_encrypt_change(struct net_buf *buf)
static void hci_encrypt_key_refresh_complete(struct net_buf *buf)
{
struct bt_hci_evt_encrypt_key_refresh_complete *evt = (void *)buf->data;
uint8_t status = evt->status;
struct bt_conn *conn;
uint16_t handle;
@ -3689,9 +3691,9 @@ static void hci_encrypt_key_refresh_complete(struct net_buf *buf)
return;
}
if (evt->status) {
bt_conn_security_changed(conn, evt->status,
bt_security_err_get(evt->status));
if (status) {
bt_conn_security_changed(conn, status,
bt_security_err_get(status));
bt_conn_unref(conn);
return;
}
@ -3705,7 +3707,10 @@ static void hci_encrypt_key_refresh_complete(struct net_buf *buf)
#if defined(CONFIG_BT_SMP)
if (conn->type == BT_CONN_TYPE_LE) {
bt_smp_update_keys(conn);
update_sec_level(conn);
if (!update_sec_level(conn)) {
status = BT_HCI_ERR_AUTH_FAIL;
}
}
#endif /* CONFIG_BT_SMP */
#if defined(CONFIG_BT_BREDR)
@ -3717,7 +3722,12 @@ static void hci_encrypt_key_refresh_complete(struct net_buf *buf)
}
#endif /* CONFIG_BT_BREDR */
bt_conn_security_changed(conn, evt->status, BT_SECURITY_ERR_SUCCESS);
bt_conn_security_changed(conn, status, bt_security_err_get(status));
if (status) {
BT_ERR("Failed to set required security level");
bt_conn_disconnect(conn, status);
}
bt_conn_unref(conn);
}
#endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */

View file

@ -439,7 +439,6 @@ static enum bt_security_err security_err_get(uint8_t smp_err)
}
}
#if defined(CONFIG_BT_SMP_APP_PAIRING_ACCEPT)
static uint8_t smp_err_get(enum bt_security_err auth_err)
{
switch (auth_err) {
@ -464,7 +463,6 @@ static uint8_t smp_err_get(enum bt_security_err auth_err)
return 0;
}
}
#endif /* CONFIG_BT_SMP_APP_PAIRING_ACCEPT */
static struct net_buf *smp_create_pdu(struct bt_smp *smp, uint8_t op, size_t len)
{
@ -4536,9 +4534,24 @@ static void bt_smp_encrypt_change(struct bt_l2cap_chan *chan,
BT_DBG("chan %p conn %p handle %u encrypt 0x%02x hci status 0x%02x",
chan, conn, conn->handle, conn->encrypt, hci_status);
atomic_clear_bit(smp->flags, SMP_FLAG_ENC_PENDING);
if (!atomic_test_and_clear_bit(smp->flags, SMP_FLAG_ENC_PENDING)) {
/* We where not waiting for encryption procedure.
* This happens when encrypt change is called to notify that
* security has failed before starting encryption.
*/
return;
}
if (hci_status) {
if (atomic_test_bit(smp->flags, SMP_FLAG_PAIRING)) {
uint8_t smp_err = smp_err_get(
bt_security_err_get(hci_status));
/* Fail as if it happened during key distribution */
atomic_set_bit(smp->flags, SMP_FLAG_KEYS_DISTR);
smp_pairing_complete(smp, smp_err);
}
return;
}