Commit 2ae9e277 authored by Joakim Andersson's avatar Joakim Andersson Committed by Anas Nashif
Browse files

Bluetooth: SMP: Re-pairing cannot lower the security level of the bond

Make sure that a new pairing procedure with an existing bond does not
result in a security with weaker security properties.

Signed-off-by: default avatarJoakim Andersson <joakim.andersson@nordicsemi.no>
parent abe47b70
Loading
Loading
Loading
Loading
+67 −12
Changes for subsys/bluetooth/host/smp.c: 67 added lines, 12 removed lines.
Original line number Diff line number Diff line
@@ -294,10 +294,20 @@ no_callbacks:
	}
}

#if !defined(CONFIG_BT_SMP_SC_PAIR_ONLY)
static u8_t legacy_get_pair_method(struct bt_smp *smp, u8_t remote_io);
#endif

static u8_t get_pair_method(struct bt_smp *smp, u8_t remote_io)
{
	struct bt_smp_pairing *req, *rsp;

#if !defined(CONFIG_BT_SMP_SC_PAIR_ONLY)
	if (!atomic_test_bit(smp->flags, SMP_FLAG_SC)) {
		return legacy_get_pair_method(smp, remote_io);
	}
#endif

	if (remote_io > BT_SMP_IO_KEYBOARD_DISPLAY)
		return JUST_WORKS;

@@ -541,6 +551,39 @@ static u8_t get_encryption_key_size(struct bt_smp *smp)
	return MIN(req->max_key_size, rsp->max_key_size);
}

/* Check that if a new pairing procedure with an existing bond will not lower
 * the established security level of the bond.
 */
bool update_keys_check(struct bt_smp *smp)
{
	struct bt_conn *conn = smp->chan.chan.conn;

	if (!conn->le.keys) {
		conn->le.keys = bt_keys_get_addr(conn->id, &conn->le.dst);
	}

	if (!conn->le.keys ||
	    !(conn->le.keys->keys & (BT_KEYS_LTK_P256 | BT_KEYS_LTK))) {
		return true;
	}

	if (conn->le.keys->enc_size > get_encryption_key_size(smp)) {
		return false;
	}

	if ((conn->le.keys->keys & BT_KEYS_LTK_P256) &&
	    !atomic_test_bit(smp->flags, SMP_FLAG_SC)) {
		return false;
	}

	if ((conn->le.keys->flags & BT_KEYS_AUTHENTICATED) &&
	     smp->method == JUST_WORKS) {
		return false;
	}

	return true;
}

#if defined(CONFIG_BT_PRIVACY) || defined(CONFIG_BT_SIGNING) || \
	!defined(CONFIG_BT_SMP_SC_PAIR_ONLY)
/* For TX callbacks */
@@ -2001,14 +2044,12 @@ static u8_t legacy_send_pairing_confirm(struct bt_smp *smp)
}

#if defined(CONFIG_BT_PERIPHERAL)
static u8_t legacy_pairing_req(struct bt_smp *smp, u8_t remote_io)
static u8_t legacy_pairing_req(struct bt_smp *smp)
{
	u8_t ret;

	BT_DBG("");

	smp->method = legacy_get_pair_method(smp, remote_io);

	/* ask for consent if pairing is not due to sending SecReq*/
	if ((DISPLAY_FIXED(smp) || smp->method == JUST_WORKS) &&
	    !atomic_test_bit(smp->flags, SMP_FLAG_SEC_REQ) &&
@@ -2207,14 +2248,12 @@ static u8_t smp_master_ident(struct bt_smp *smp, struct net_buf *buf)
}

#if defined(CONFIG_BT_CENTRAL)
static u8_t legacy_pairing_rsp(struct bt_smp *smp, u8_t remote_io)
static u8_t legacy_pairing_rsp(struct bt_smp *smp)
{
	u8_t ret;

	BT_DBG("");

	smp->method = legacy_get_pair_method(smp, remote_io);

	/* ask for consent if this is due to received SecReq */
	if ((DISPLAY_FIXED(smp) || smp->method == JUST_WORKS) &&
	    atomic_test_bit(smp->flags, SMP_FLAG_SEC_REQ) &&
@@ -2442,16 +2481,20 @@ static u8_t smp_pairing_req(struct bt_smp *smp, struct net_buf *buf)

	atomic_set_bit(smp->flags, SMP_FLAG_PAIRING);

	smp->method = get_pair_method(smp, req->io_capability);

	if (!update_keys_check(smp)) {
		return BT_SMP_ERR_AUTH_REQUIREMENTS;
	}

	if (!atomic_test_bit(smp->flags, SMP_FLAG_SC)) {
#if defined(CONFIG_BT_SMP_SC_PAIR_ONLY)
		return BT_SMP_ERR_AUTH_REQUIREMENTS;
#else
		return legacy_pairing_req(smp, req->io_capability);
		return legacy_pairing_req(smp);
#endif /* CONFIG_BT_SMP_SC_PAIR_ONLY */
	}

	smp->method = get_pair_method(smp, req->io_capability);

	if ((IS_ENABLED(CONFIG_BT_SMP_SC_ONLY) ||
	     conn->required_sec_level == BT_SECURITY_FIPS) &&
		smp->method == JUST_WORKS) {
@@ -2604,16 +2647,20 @@ static u8_t smp_pairing_rsp(struct bt_smp *smp, struct net_buf *buf)
		atomic_set_bit(smp->flags, SMP_FLAG_BOND);
	}

	smp->method = get_pair_method(smp, rsp->io_capability);

	if (!update_keys_check(smp)) {
		return BT_SMP_ERR_AUTH_REQUIREMENTS;
	}

	if (!atomic_test_bit(smp->flags, SMP_FLAG_SC)) {
#if defined(CONFIG_BT_SMP_SC_PAIR_ONLY)
		return BT_SMP_ERR_AUTH_REQUIREMENTS;
#else
		return legacy_pairing_rsp(smp, rsp->io_capability);
		return legacy_pairing_rsp(smp);
#endif /* CONFIG_BT_SMP_SC_PAIR_ONLY */
	}

	smp->method = get_pair_method(smp, rsp->io_capability);

	if ((IS_ENABLED(CONFIG_BT_SMP_SC_ONLY) ||
	     conn->required_sec_level == BT_SECURITY_FIPS) &&
	     smp->method == JUST_WORKS) {
@@ -3368,6 +3415,14 @@ static u8_t smp_public_key(struct bt_smp *smp, struct net_buf *buf)
	if (memcmp(smp->pkey, sc_debug_public_key, 64) == 0) {
		BT_INFO("Remote is using Debug Public key");
		atomic_set_bit(smp->flags, SMP_FLAG_SC_DEBUG_KEY);

		/* Don't allow a bond established without debug key to be
		 * updated using LTK generated from debug key.
		 */
		if (smp->chan.chan.conn->le.keys &&
		    !(smp->chan.chan.conn->le.keys->flags & BT_KEYS_DEBUG)) {
			return BT_SMP_ERR_AUTH_REQUIREMENTS;
		}
	}

	if (IS_ENABLED(CONFIG_BT_CENTRAL) &&