Commit d3e54a87 authored by Johan Hedberg's avatar Johan Hedberg Committed by Marcel Holtmann

Bluetooth: Fix DHKey Check sending order for slave role

According to the LE SC specification the initiating device sends its
DHKey check first and the non-initiating devices sends its DHKey check
as a response to this. It's also important that the non-initiating
device doesn't send the response if it's still waiting for user input.
In order to synchronize all this a new flag is added.
Signed-off-by: default avatarJohan Hedberg <johan.hedberg@intel.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 38606f14
...@@ -56,6 +56,7 @@ enum { ...@@ -56,6 +56,7 @@ enum {
SMP_FLAG_REMOTE_PK, SMP_FLAG_REMOTE_PK,
SMP_FLAG_DEBUG_KEY, SMP_FLAG_DEBUG_KEY,
SMP_FLAG_WAIT_USER, SMP_FLAG_WAIT_USER,
SMP_FLAG_DHKEY_PENDING,
}; };
struct smp_chan { struct smp_chan {
...@@ -994,6 +995,29 @@ static void smp_notify_keys(struct l2cap_conn *conn) ...@@ -994,6 +995,29 @@ static void smp_notify_keys(struct l2cap_conn *conn)
} }
} }
static void sc_add_ltk(struct smp_chan *smp)
{
struct hci_conn *hcon = smp->conn->hcon;
u8 key_type, auth;
if (test_bit(SMP_FLAG_DEBUG_KEY, &smp->flags))
key_type = SMP_LTK_P256_DEBUG;
else
key_type = SMP_LTK_P256;
if (hcon->pending_sec_level == BT_SECURITY_FIPS)
auth = 1;
else
auth = 0;
memset(smp->tk + smp->enc_key_size, 0,
SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
smp->ltk = hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type,
key_type, auth, smp->tk, smp->enc_key_size,
0, 0);
}
static void sc_generate_link_key(struct smp_chan *smp) static void sc_generate_link_key(struct smp_chan *smp)
{ {
/* These constants are as specified in the core specification. /* These constants are as specified in the core specification.
...@@ -1312,12 +1336,10 @@ static u8 sc_passkey_round(struct smp_chan *smp, u8 smp_op) ...@@ -1312,12 +1336,10 @@ static u8 sc_passkey_round(struct smp_chan *smp, u8 smp_op)
if (!hcon->out) { if (!hcon->out) {
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM,
sizeof(smp->prnd), smp->prnd); sizeof(smp->prnd), smp->prnd);
if (smp->passkey_round == 20) { if (smp->passkey_round == 20)
sc_dhkey_check(smp);
SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK); SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
} else { else
SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM); SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM);
}
return 0; return 0;
} }
...@@ -1394,7 +1416,14 @@ static int sc_user_reply(struct smp_chan *smp, u16 mgmt_op, __le32 passkey) ...@@ -1394,7 +1416,14 @@ static int sc_user_reply(struct smp_chan *smp, u16 mgmt_op, __le32 passkey)
return 0; return 0;
} }
sc_dhkey_check(smp); /* Initiator sends DHKey check first */
if (hcon->out) {
sc_dhkey_check(smp);
SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
} else if (test_and_clear_bit(SMP_FLAG_DHKEY_PENDING, &smp->flags)) {
sc_dhkey_check(smp);
sc_add_ltk(smp);
}
return 0; return 0;
} }
...@@ -2262,7 +2291,6 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -2262,7 +2291,6 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb)
struct smp_chan *smp = chan->data; struct smp_chan *smp = chan->data;
u8 a[7], b[7], *local_addr, *remote_addr; u8 a[7], b[7], *local_addr, *remote_addr;
u8 io_cap[3], r[16], e[16]; u8 io_cap[3], r[16], e[16];
u8 key_type, auth;
int err; int err;
BT_DBG("conn %p", conn); BT_DBG("conn %p", conn);
...@@ -2298,19 +2326,17 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -2298,19 +2326,17 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb)
if (memcmp(check->e, e, 16)) if (memcmp(check->e, e, 16))
return SMP_DHKEY_CHECK_FAILED; return SMP_DHKEY_CHECK_FAILED;
if (test_bit(SMP_FLAG_DEBUG_KEY, &smp->flags)) if (!hcon->out) {
key_type = SMP_LTK_P256_DEBUG; if (test_bit(SMP_FLAG_WAIT_USER, &smp->flags)) {
else set_bit(SMP_FLAG_DHKEY_PENDING, &smp->flags);
key_type = SMP_LTK_P256; return 0;
}
if (hcon->pending_sec_level == BT_SECURITY_FIPS) /* Slave sends DHKey check as response to master */
auth = 1; sc_dhkey_check(smp);
else }
auth = 0;
smp->ltk = hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type, sc_add_ltk(smp);
key_type, auth, smp->tk, smp->enc_key_size,
0, 0);
if (hcon->out) { if (hcon->out) {
hci_le_start_enc(hcon, 0, 0, smp->tk); hci_le_start_enc(hcon, 0, 0, smp->tk);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment