Bluetooth: SMP: Add support for Link Key derivation
This allows to derive BR/EDR Link Key from LE SC LTK so no further BR/EDR pairing is needed to encrypt BR/EDR link with key as strong as LTK. Change-Id: Ie28e9ec7a250189b122f1bce291fa9468a758614 Signed-off-by: Szymon Janc <ext.szymon.janc@tieto.com>
This commit is contained in:
parent
e2b5be9087
commit
d3bd10dda1
2 changed files with 110 additions and 4 deletions
|
@ -84,6 +84,7 @@ void bt_keys_clear(struct bt_keys *keys);
|
|||
enum {
|
||||
BT_LINK_KEY_AUTHENTICATED,
|
||||
BT_LINK_KEY_DEBUG,
|
||||
BT_LINK_KEY_SC,
|
||||
|
||||
/* Total number of flags - must be at the end of the enum */
|
||||
BT_LINK_KEY_NUM_FLAGS,
|
||||
|
|
|
@ -68,11 +68,18 @@
|
|||
#define ID_DIST 0
|
||||
#endif
|
||||
|
||||
#define RECV_KEYS (BT_SMP_DIST_ENC_KEY | BT_SMP_DIST_ID_KEY | SIGN_DIST)
|
||||
#define SEND_KEYS (BT_SMP_DIST_ENC_KEY | ID_DIST | SIGN_DIST)
|
||||
#if defined(CONFIG_BLUETOOTH_BREDR)
|
||||
#define LINK_DIST BT_SMP_DIST_LINK_KEY
|
||||
#else
|
||||
#define LINK_DIST 0
|
||||
#endif
|
||||
|
||||
#define RECV_KEYS_SC (RECV_KEYS & ~(BT_SMP_DIST_ENC_KEY | BT_SMP_DIST_LINK_KEY))
|
||||
#define SEND_KEYS_SC (SEND_KEYS & ~(BT_SMP_DIST_ENC_KEY | BT_SMP_DIST_LINK_KEY))
|
||||
#define RECV_KEYS (BT_SMP_DIST_ENC_KEY | BT_SMP_DIST_ID_KEY | SIGN_DIST |\
|
||||
LINK_DIST)
|
||||
#define SEND_KEYS (BT_SMP_DIST_ENC_KEY | ID_DIST | SIGN_DIST | LINK_DIST)
|
||||
|
||||
#define RECV_KEYS_SC (RECV_KEYS & ~(BT_SMP_DIST_ENC_KEY))
|
||||
#define SEND_KEYS_SC (SEND_KEYS & ~(BT_SMP_DIST_ENC_KEY))
|
||||
|
||||
#define BT_SMP_AUTH_MASK 0x07
|
||||
#define BT_SMP_AUTH_MASK_SC 0x0f
|
||||
|
@ -100,6 +107,7 @@ enum {
|
|||
SMP_FLAG_SC_DEBUG_KEY, /* if Secure Connection are using debug key */
|
||||
SMP_FLAG_SEC_REQ, /* if Security Request was sent/received */
|
||||
SMP_FLAG_DHCHECK_WAIT, /* if waiting for remote DHCheck (as slave) */
|
||||
SMP_FLAG_DERIVE_LK, /* if Link Key should be derived */
|
||||
|
||||
/* Total number of flags - must be at the end */
|
||||
SMP_NUM_FLAGS,
|
||||
|
@ -536,6 +544,72 @@ static int smp_g2(const uint8_t u[32], const uint8_t v[32],
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BLUETOOTH_BREDR)
|
||||
static int smp_h6(const uint8_t w[16], const uint8_t key_id[4], uint8_t res[16])
|
||||
{
|
||||
uint8_t ws[16];
|
||||
uint8_t key_id_s[4];
|
||||
int err;
|
||||
|
||||
BT_DBG("w %s", bt_hex(w, 16));
|
||||
BT_DBG("key_id %s", bt_hex(key_id, 4));
|
||||
|
||||
swap_buf(ws, w, 16);
|
||||
swap_buf(key_id_s, key_id, 4);
|
||||
|
||||
err = bt_smp_aes_cmac(ws, key_id_s, 4, res);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
BT_DBG("res %s", bt_hex(res, 16));
|
||||
|
||||
swap_in_place(res, 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sc_derive_link_key(struct bt_smp *smp)
|
||||
{
|
||||
/* constants as specified in Core Spec Vol.3 Part H 2.4.2.4 */
|
||||
static const uint8_t tmp1[4] = { 0x31, 0x70, 0x6d, 0x74 };
|
||||
static const uint8_t lebr[4] = { 0x72, 0x62, 0x65, 0x6c };
|
||||
struct bt_conn *conn = smp->chan.chan.conn;
|
||||
struct bt_keys_link_key *link_key;
|
||||
uint8_t ilk[16];
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
/* TODO handle errors? */
|
||||
|
||||
/*
|
||||
* At this point remote device identity is known so we can use
|
||||
* destination address here
|
||||
*/
|
||||
link_key = bt_keys_get_link_key(&conn->le.dst.a);
|
||||
if (!link_key) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (smp_h6(conn->le.keys->ltk.val, tmp1, ilk)) {
|
||||
bt_keys_link_key_clear(link_key);
|
||||
return;
|
||||
}
|
||||
|
||||
if (smp_h6(ilk, lebr, link_key->val)) {
|
||||
bt_keys_link_key_clear(link_key);
|
||||
}
|
||||
|
||||
atomic_set_bit(link_key->flags, BT_LINK_KEY_SC);
|
||||
|
||||
if (atomic_test_bit(conn->le.keys->flags, BT_KEYS_AUTHENTICATED)) {
|
||||
atomic_set_bit(link_key->flags, BT_LINK_KEY_AUTHENTICATED);
|
||||
} else {
|
||||
atomic_clear_bit(link_key->flags, BT_LINK_KEY_AUTHENTICATED);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_BLUETOOTH_BREDR */
|
||||
|
||||
static void smp_reset(struct bt_smp *smp)
|
||||
{
|
||||
struct bt_conn *conn = smp->chan.chan.conn;
|
||||
|
@ -568,6 +642,19 @@ static void smp_pairing_complete(struct bt_smp *smp, uint8_t status)
|
|||
{
|
||||
BT_DBG("status 0x%x", status);
|
||||
|
||||
#if defined(CONFIG_BLUETOOTH_BREDR)
|
||||
if (!status) {
|
||||
/*
|
||||
* Don't derive if Debug Keys are used.
|
||||
* TODO should we allow this if BR/EDR is already connected?
|
||||
*/
|
||||
if (atomic_test_bit(smp->flags, SMP_FLAG_DERIVE_LK) &&
|
||||
!atomic_test_bit(smp->flags, SMP_FLAG_SC_DEBUG_KEY)) {
|
||||
sc_derive_link_key(smp);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_BLUETOOTH_BREDR */
|
||||
|
||||
smp_reset(smp);
|
||||
}
|
||||
|
||||
|
@ -2667,6 +2754,24 @@ static void bt_smp_encrypt_change(struct bt_l2cap_chan *chan)
|
|||
return;
|
||||
}
|
||||
|
||||
/* derive BR/EDR LinkKey if supported by both sides */
|
||||
if (atomic_test_bit(smp->flags, SMP_FLAG_SC)) {
|
||||
if ((smp->local_dist & BT_SMP_DIST_LINK_KEY) &&
|
||||
(smp->remote_dist & BT_SMP_DIST_LINK_KEY)) {
|
||||
/*
|
||||
* Link Key will be derived after key distribution to
|
||||
* make sure remote device identity is known
|
||||
*/
|
||||
atomic_set_bit(smp->flags, SMP_FLAG_DERIVE_LK);
|
||||
}
|
||||
/*
|
||||
* Those are used as pairing finished indicator so generated
|
||||
* but not distributed keys must be cleared here.
|
||||
*/
|
||||
smp->local_dist &= ~BT_SMP_DIST_LINK_KEY;
|
||||
smp->remote_dist &= ~BT_SMP_DIST_LINK_KEY;
|
||||
}
|
||||
|
||||
if (smp->remote_dist & BT_SMP_DIST_ENC_KEY) {
|
||||
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_ENCRYPT_INFO);
|
||||
} else if (smp->remote_dist & BT_SMP_DIST_ID_KEY) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue