Skip to content
Open
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
4 changes: 4 additions & 0 deletions doc/releases/migration-guide-4.4.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ Bluetooth Host
* :c:member:`bt_conn_le_info.interval` has been deprecated. Use
:c:member:`bt_conn_le_info.interval_us` instead. Note that the units have changed: ``interval``
was in units of 1.25 milliseconds, while ``interval_us`` is in microseconds.
* Legacy Bluetooth LE pairing using the passkey entry method no longer grants authenticated (MITM)
protection as of the Bluetooth Core Specification v6.2. Stored bonds that were generated using
this method will be downgraded to unauthenticated when loaded from persistent storage, resulting
in a lower security level.

Networking
**********
Expand Down
9 changes: 9 additions & 0 deletions subsys/bluetooth/host/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1138,6 +1138,15 @@ config BT_CONN_DISABLE_SECURITY
WARNING: This option enables anyone to snoop on-air traffic.
Use of this feature in production is strongly discouraged.

config BT_SMP_LEGACY_PAIR_ONLY
bool "Force legacy pairing"
depends on BT_TESTING
depends on !(BT_SMP_SC_PAIR_ONLY || BT_SMP_SC_ONLY)
help
This option enforces legacy pairing. This is required for testing
legacy pairing between two Zephyr Bluetooth devices, as without this
option the devices will default to using Secure Connections pairing.

rsource "./classic/Kconfig"

config BT_HCI_VS_EVT_USER
Expand Down
12 changes: 12 additions & 0 deletions subsys/bluetooth/host/keys.c
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,18 @@ static int keys_set(const char *name, size_t len_rd, settings_read_cb read_cb,
memcpy(keys->storage_start, val, len);
}

/* As of Core v6.2, authenticated keys are only valid for OOB or LE SC pairing
* methods. This check ensures that keys are valid if a device is updated from a
* previous version that did not enforce this requirement.
*/
if ((keys->flags & BT_KEYS_AUTHENTICATED) &&
!((keys->flags & BT_KEYS_OOB) || (keys->flags & BT_KEYS_SC))) {
LOG_WRN("The keys for %s are downgraded to unauthenticated as they no longer meet "
"authentication requirements",
bt_addr_le_str(&addr));
keys->flags &= ~BT_KEYS_AUTHENTICATED;
}

check_and_set_id_conflict_flag(keys);

LOG_DBG("Successfully restored keys for %s", bt_addr_le_str(&addr));
Expand Down
36 changes: 23 additions & 13 deletions subsys/bluetooth/host/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,21 +92,21 @@ LOG_MODULE_REGISTER(bt_smp);
#if defined(CONFIG_BT_CLASSIC)

#define BT_SMP_AUTH_MASK_SC 0x2f
#if defined(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY)
#if defined(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY) || defined(CONFIG_BT_SMP_LEGACY_PAIR_ONLY)
#define BT_SMP_AUTH_DEFAULT (BT_SMP_AUTH_BONDING_FLAGS | BT_SMP_AUTH_CT2)
#else
#define BT_SMP_AUTH_DEFAULT (BT_SMP_AUTH_BONDING_FLAGS | BT_SMP_AUTH_CT2 |\
BT_SMP_AUTH_SC)
#endif /* CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY */
#endif /* CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY || CONFIG_BT_SMP_LEGACY_PAIR_ONLY */

#else

#define BT_SMP_AUTH_MASK_SC 0x0f
#if defined(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY)
#if defined(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY) || defined(CONFIG_BT_SMP_LEGACY_PAIR_ONLY)
#define BT_SMP_AUTH_DEFAULT (BT_SMP_AUTH_BONDING_FLAGS)
#else
#define BT_SMP_AUTH_DEFAULT (BT_SMP_AUTH_BONDING_FLAGS | BT_SMP_AUTH_SC)
#endif /* CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY */
#endif /* CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY || CONFIG_BT_SMP_LEGACY_PAIR_ONLY */

#endif /* CONFIG_BT_CLASSIC */

Expand Down Expand Up @@ -321,7 +321,8 @@ static struct {

static bool le_sc_supported(void)
{
if (IS_ENABLED(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY)) {
if (IS_ENABLED(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY) ||
IS_ENABLED(CONFIG_BT_SMP_LEGACY_PAIR_ONLY)) {
return false;
}

Expand Down Expand Up @@ -666,7 +667,9 @@ static bool update_keys_check(struct bt_smp *smp, struct bt_keys *keys)
}

if ((keys->flags & BT_KEYS_AUTHENTICATED) &&
smp->method == JUST_WORKS) {
((smp->method == JUST_WORKS) ||
(!atomic_test_bit(smp->flags, SMP_FLAG_SC) &&
(smp->method == PASSKEY_DISPLAY || smp->method == PASSKEY_INPUT)))) {
return false;
}

Expand Down Expand Up @@ -2491,11 +2494,12 @@ static uint8_t legacy_request_tk(struct bt_smp *smp)
* Fail if we have keys that are stronger than keys that will be
* distributed in new pairing. This is to avoid replacing authenticated
* keys with unauthenticated ones.
*/
*/
keys = bt_keys_find_addr(conn->id, &conn->le.dst);
if (keys && (keys->flags & BT_KEYS_AUTHENTICATED) &&
smp->method == JUST_WORKS) {
LOG_ERR("JustWorks failed, authenticated keys present");
(smp->method == JUST_WORKS || smp->method == PASSKEY_DISPLAY ||
smp->method == PASSKEY_INPUT)) {
LOG_ERR("Pairing failed, authenticated keys present");
return BT_SMP_ERR_UNSPECIFIED;
}

Expand Down Expand Up @@ -2983,7 +2987,9 @@ static uint8_t remote_sec_level_reachable(struct bt_smp *smp)
}
__fallthrough;
case BT_SECURITY_L3:
if (smp->method == JUST_WORKS) {
if (smp->method == JUST_WORKS ||
(!atomic_test_bit(smp->flags, SMP_FLAG_SC) &&
(smp->method == PASSKEY_DISPLAY || smp->method == PASSKEY_INPUT))) {
return BT_SMP_ERR_AUTH_REQUIREMENTS;
}

Expand Down Expand Up @@ -6327,12 +6333,16 @@ void bt_smp_update_keys(struct bt_conn *conn)
case LE_SC_OOB:
case LEGACY_OOB:
conn->le.keys->flags |= BT_KEYS_OOB;
/* fallthrough */
conn->le.keys->flags |= BT_KEYS_AUTHENTICATED;
break;
case PASSKEY_DISPLAY:
case PASSKEY_INPUT:
case PASSKEY_CONFIRM:
conn->le.keys->flags |= BT_KEYS_AUTHENTICATED;
break;
if (atomic_test_bit(smp->flags, SMP_FLAG_SC)) {
conn->le.keys->flags |= BT_KEYS_AUTHENTICATED;
break;
}
/* fallthrough */
case JUST_WORKS:
default:
/* unauthenticated key, clear it */
Expand Down