|
@@ -385,6 +385,16 @@ static const u8 gen_method[5][5] = {
|
|
{ CFM_PASSKEY, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, OVERLAP },
|
|
{ CFM_PASSKEY, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, OVERLAP },
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+static u8 get_auth_method(struct smp_chan *smp, u8 local_io, u8 remote_io)
|
|
|
|
+{
|
|
|
|
+ /* If either side has unknown io_caps, use JUST WORKS */
|
|
|
|
+ if (local_io > SMP_IO_KEYBOARD_DISPLAY ||
|
|
|
|
+ remote_io > SMP_IO_KEYBOARD_DISPLAY)
|
|
|
|
+ return JUST_WORKS;
|
|
|
|
+
|
|
|
|
+ return gen_method[remote_io][local_io];
|
|
|
|
+}
|
|
|
|
+
|
|
static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
|
|
static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
|
|
u8 local_io, u8 remote_io)
|
|
u8 local_io, u8 remote_io)
|
|
{
|
|
{
|
|
@@ -401,14 +411,11 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
|
|
BT_DBG("tk_request: auth:%d lcl:%d rem:%d", auth, local_io, remote_io);
|
|
BT_DBG("tk_request: auth:%d lcl:%d rem:%d", auth, local_io, remote_io);
|
|
|
|
|
|
/* If neither side wants MITM, use JUST WORKS */
|
|
/* If neither side wants MITM, use JUST WORKS */
|
|
- /* If either side has unknown io_caps, use JUST WORKS */
|
|
|
|
/* Otherwise, look up method from the table */
|
|
/* Otherwise, look up method from the table */
|
|
- if (!(auth & SMP_AUTH_MITM) ||
|
|
|
|
- local_io > SMP_IO_KEYBOARD_DISPLAY ||
|
|
|
|
- remote_io > SMP_IO_KEYBOARD_DISPLAY)
|
|
|
|
|
|
+ if (!(auth & SMP_AUTH_MITM))
|
|
method = JUST_WORKS;
|
|
method = JUST_WORKS;
|
|
else
|
|
else
|
|
- method = gen_method[remote_io][local_io];
|
|
|
|
|
|
+ method = get_auth_method(smp, local_io, remote_io);
|
|
|
|
|
|
/* If not bonding, don't ask user to confirm a Zero TK */
|
|
/* If not bonding, don't ask user to confirm a Zero TK */
|
|
if (!(auth & SMP_AUTH_BONDING) && method == JUST_CFM)
|
|
if (!(auth & SMP_AUTH_BONDING) && method == JUST_CFM)
|
|
@@ -544,7 +551,7 @@ static u8 smp_random(struct smp_chan *smp)
|
|
hci_le_start_enc(hcon, ediv, rand, stk);
|
|
hci_le_start_enc(hcon, ediv, rand, stk);
|
|
hcon->enc_key_size = smp->enc_key_size;
|
|
hcon->enc_key_size = smp->enc_key_size;
|
|
} else {
|
|
} else {
|
|
- u8 stk[16];
|
|
|
|
|
|
+ u8 stk[16], auth;
|
|
__le64 rand = 0;
|
|
__le64 rand = 0;
|
|
__le16 ediv = 0;
|
|
__le16 ediv = 0;
|
|
|
|
|
|
@@ -556,8 +563,13 @@ static u8 smp_random(struct smp_chan *smp)
|
|
memset(stk + smp->enc_key_size, 0,
|
|
memset(stk + smp->enc_key_size, 0,
|
|
SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
|
|
SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
|
|
|
|
|
|
|
|
+ if (hcon->pending_sec_level == BT_SECURITY_HIGH)
|
|
|
|
+ auth = 1;
|
|
|
|
+ else
|
|
|
|
+ auth = 0;
|
|
|
|
+
|
|
hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type,
|
|
hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type,
|
|
- HCI_SMP_STK_SLAVE, 0, stk, smp->enc_key_size,
|
|
|
|
|
|
+ HCI_SMP_STK_SLAVE, auth, stk, smp->enc_key_size,
|
|
ediv, rand);
|
|
ediv, rand);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -664,7 +676,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
|
{
|
|
{
|
|
struct smp_cmd_pairing rsp, *req = (void *) skb->data;
|
|
struct smp_cmd_pairing rsp, *req = (void *) skb->data;
|
|
struct smp_chan *smp;
|
|
struct smp_chan *smp;
|
|
- u8 key_size, auth;
|
|
|
|
|
|
+ u8 key_size, auth, sec_level;
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
BT_DBG("conn %p", conn);
|
|
BT_DBG("conn %p", conn);
|
|
@@ -690,7 +702,19 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
|
/* We didn't start the pairing, so match remote */
|
|
/* We didn't start the pairing, so match remote */
|
|
auth = req->auth_req;
|
|
auth = req->auth_req;
|
|
|
|
|
|
- conn->hcon->pending_sec_level = authreq_to_seclevel(auth);
|
|
|
|
|
|
+ sec_level = authreq_to_seclevel(auth);
|
|
|
|
+ if (sec_level > conn->hcon->pending_sec_level)
|
|
|
|
+ conn->hcon->pending_sec_level = sec_level;
|
|
|
|
+
|
|
|
|
+ /* If we need MITM check that it can be acheived */
|
|
|
|
+ if (conn->hcon->pending_sec_level >= BT_SECURITY_HIGH) {
|
|
|
|
+ u8 method;
|
|
|
|
+
|
|
|
|
+ method = get_auth_method(smp, conn->hcon->io_capability,
|
|
|
|
+ req->io_capability);
|
|
|
|
+ if (method == JUST_WORKS || method == JUST_CFM)
|
|
|
|
+ return SMP_AUTH_REQUIREMENTS;
|
|
|
|
+ }
|
|
|
|
|
|
build_pairing_cmd(conn, req, &rsp, auth);
|
|
build_pairing_cmd(conn, req, &rsp, auth);
|
|
|
|
|
|
@@ -738,6 +762,16 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
|
|
if (check_enc_key_size(conn, key_size))
|
|
if (check_enc_key_size(conn, key_size))
|
|
return SMP_ENC_KEY_SIZE;
|
|
return SMP_ENC_KEY_SIZE;
|
|
|
|
|
|
|
|
+ /* If we need MITM check that it can be acheived */
|
|
|
|
+ if (conn->hcon->pending_sec_level >= BT_SECURITY_HIGH) {
|
|
|
|
+ u8 method;
|
|
|
|
+
|
|
|
|
+ method = get_auth_method(smp, req->io_capability,
|
|
|
|
+ rsp->io_capability);
|
|
|
|
+ if (method == JUST_WORKS || method == JUST_CFM)
|
|
|
|
+ return SMP_AUTH_REQUIREMENTS;
|
|
|
|
+ }
|
|
|
|
+
|
|
get_random_bytes(smp->prnd, sizeof(smp->prnd));
|
|
get_random_bytes(smp->prnd, sizeof(smp->prnd));
|
|
|
|
|
|
smp->prsp[0] = SMP_CMD_PAIRING_RSP;
|
|
smp->prsp[0] = SMP_CMD_PAIRING_RSP;
|
|
@@ -833,6 +867,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
|
struct smp_cmd_pairing cp;
|
|
struct smp_cmd_pairing cp;
|
|
struct hci_conn *hcon = conn->hcon;
|
|
struct hci_conn *hcon = conn->hcon;
|
|
struct smp_chan *smp;
|
|
struct smp_chan *smp;
|
|
|
|
+ u8 sec_level;
|
|
|
|
|
|
BT_DBG("conn %p", conn);
|
|
BT_DBG("conn %p", conn);
|
|
|
|
|
|
@@ -842,7 +877,9 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
|
if (!(conn->hcon->link_mode & HCI_LM_MASTER))
|
|
if (!(conn->hcon->link_mode & HCI_LM_MASTER))
|
|
return SMP_CMD_NOTSUPP;
|
|
return SMP_CMD_NOTSUPP;
|
|
|
|
|
|
- hcon->pending_sec_level = authreq_to_seclevel(rp->auth_req);
|
|
|
|
|
|
+ sec_level = authreq_to_seclevel(rp->auth_req);
|
|
|
|
+ if (sec_level > hcon->pending_sec_level)
|
|
|
|
+ hcon->pending_sec_level = sec_level;
|
|
|
|
|
|
if (smp_ltk_encrypt(conn, hcon->pending_sec_level))
|
|
if (smp_ltk_encrypt(conn, hcon->pending_sec_level))
|
|
return 0;
|
|
return 0;
|
|
@@ -896,9 +933,12 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
|
|
if (smp_sufficient_security(hcon, sec_level))
|
|
if (smp_sufficient_security(hcon, sec_level))
|
|
return 1;
|
|
return 1;
|
|
|
|
|
|
|
|
+ if (sec_level > hcon->pending_sec_level)
|
|
|
|
+ hcon->pending_sec_level = sec_level;
|
|
|
|
+
|
|
if (hcon->link_mode & HCI_LM_MASTER)
|
|
if (hcon->link_mode & HCI_LM_MASTER)
|
|
- if (smp_ltk_encrypt(conn, sec_level))
|
|
|
|
- goto done;
|
|
|
|
|
|
+ if (smp_ltk_encrypt(conn, hcon->pending_sec_level))
|
|
|
|
+ return 0;
|
|
|
|
|
|
if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
|
|
if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
|
|
return 0;
|
|
return 0;
|
|
@@ -913,7 +953,7 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
|
|
* requires it.
|
|
* requires it.
|
|
*/
|
|
*/
|
|
if (hcon->io_capability != HCI_IO_NO_INPUT_OUTPUT ||
|
|
if (hcon->io_capability != HCI_IO_NO_INPUT_OUTPUT ||
|
|
- sec_level > BT_SECURITY_MEDIUM)
|
|
|
|
|
|
+ hcon->pending_sec_level > BT_SECURITY_MEDIUM)
|
|
authreq |= SMP_AUTH_MITM;
|
|
authreq |= SMP_AUTH_MITM;
|
|
|
|
|
|
if (hcon->link_mode & HCI_LM_MASTER) {
|
|
if (hcon->link_mode & HCI_LM_MASTER) {
|
|
@@ -932,9 +972,6 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
|
|
|
|
|
|
set_bit(SMP_FLAG_INITIATOR, &smp->flags);
|
|
set_bit(SMP_FLAG_INITIATOR, &smp->flags);
|
|
|
|
|
|
-done:
|
|
|
|
- hcon->pending_sec_level = sec_level;
|
|
|
|
-
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|