Bluetooth: Add selection of the SC authentication method
This patch adds code to select the authentication method for Secure Connections based on the local and remote capabilities. A new DSP_PASSKEY method is also added for displaying the passkey - something that is not part of legacy SMP pairing. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
parent
783e057462
commit
5e3d3d9b3c
|
@ -661,6 +661,7 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason)
|
|||
#define REQ_PASSKEY 0x02
|
||||
#define CFM_PASSKEY 0x03
|
||||
#define REQ_OOB 0x04
|
||||
#define DSP_PASSKEY 0x05
|
||||
#define OVERLAP 0xFF
|
||||
|
||||
static const u8 gen_method[5][5] = {
|
||||
|
@ -671,6 +672,14 @@ static const u8 gen_method[5][5] = {
|
|||
{ CFM_PASSKEY, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, OVERLAP },
|
||||
};
|
||||
|
||||
static const u8 sc_method[5][5] = {
|
||||
{ JUST_WORKS, JUST_CFM, REQ_PASSKEY, JUST_WORKS, REQ_PASSKEY },
|
||||
{ JUST_WORKS, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, CFM_PASSKEY },
|
||||
{ DSP_PASSKEY, DSP_PASSKEY, REQ_PASSKEY, JUST_WORKS, DSP_PASSKEY },
|
||||
{ JUST_WORKS, JUST_CFM, JUST_WORKS, JUST_WORKS, JUST_CFM },
|
||||
{ DSP_PASSKEY, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, CFM_PASSKEY },
|
||||
};
|
||||
|
||||
static u8 get_auth_method(struct smp_chan *smp, u8 local_io, u8 remote_io)
|
||||
{
|
||||
/* If either side has unknown io_caps, use JUST_CFM (which gets
|
||||
|
@ -680,6 +689,9 @@ static u8 get_auth_method(struct smp_chan *smp, u8 local_io, u8 remote_io)
|
|||
remote_io > SMP_IO_KEYBOARD_DISPLAY)
|
||||
return JUST_CFM;
|
||||
|
||||
if (test_bit(SMP_FLAG_SC, &smp->flags))
|
||||
return sc_method[remote_io][local_io];
|
||||
|
||||
return gen_method[remote_io][local_io];
|
||||
}
|
||||
|
||||
|
@ -1305,6 +1317,11 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
|||
memcpy(&smp->preq[1], req, sizeof(*req));
|
||||
skb_pull(skb, sizeof(*req));
|
||||
|
||||
build_pairing_cmd(conn, req, &rsp, auth);
|
||||
|
||||
if (rsp.auth_req & SMP_AUTH_SC)
|
||||
set_bit(SMP_FLAG_SC, &smp->flags);
|
||||
|
||||
if (conn->hcon->io_capability == HCI_IO_NO_INPUT_OUTPUT)
|
||||
sec_level = BT_SECURITY_MEDIUM;
|
||||
else
|
||||
|
@ -1323,11 +1340,6 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
|||
return SMP_AUTH_REQUIREMENTS;
|
||||
}
|
||||
|
||||
build_pairing_cmd(conn, req, &rsp, auth);
|
||||
|
||||
if (rsp.auth_req & SMP_AUTH_SC)
|
||||
set_bit(SMP_FLAG_SC, &smp->flags);
|
||||
|
||||
key_size = min(req->max_key_size, rsp.max_key_size);
|
||||
if (check_enc_key_size(conn, key_size))
|
||||
return SMP_ENC_KEY_SIZE;
|
||||
|
@ -1901,12 +1913,54 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static u8 sc_select_method(struct smp_chan *smp)
|
||||
{
|
||||
struct l2cap_conn *conn = smp->conn;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct smp_cmd_pairing *local, *remote;
|
||||
u8 local_mitm, remote_mitm, local_io, remote_io, method;
|
||||
|
||||
/* The preq/prsp contain the raw Pairing Request/Response PDUs
|
||||
* which are needed as inputs to some crypto functions. To get
|
||||
* the "struct smp_cmd_pairing" from them we need to skip the
|
||||
* first byte which contains the opcode.
|
||||
*/
|
||||
if (hcon->out) {
|
||||
local = (void *) &smp->preq[1];
|
||||
remote = (void *) &smp->prsp[1];
|
||||
} else {
|
||||
local = (void *) &smp->prsp[1];
|
||||
remote = (void *) &smp->preq[1];
|
||||
}
|
||||
|
||||
local_io = local->io_capability;
|
||||
remote_io = remote->io_capability;
|
||||
|
||||
local_mitm = (local->auth_req & SMP_AUTH_MITM);
|
||||
remote_mitm = (remote->auth_req & SMP_AUTH_MITM);
|
||||
|
||||
/* If either side wants MITM, look up the method from the table,
|
||||
* otherwise use JUST WORKS.
|
||||
*/
|
||||
if (local_mitm || remote_mitm)
|
||||
method = get_auth_method(smp, local_io, remote_io);
|
||||
else
|
||||
method = JUST_WORKS;
|
||||
|
||||
/* Don't confirm locally initiated pairing attempts */
|
||||
if (method == JUST_CFM && test_bit(SMP_FLAG_INITIATOR, &smp->flags))
|
||||
method = JUST_WORKS;
|
||||
|
||||
return method;
|
||||
}
|
||||
|
||||
static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
{
|
||||
struct smp_cmd_public_key *key = (void *) skb->data;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct l2cap_chan *chan = conn->smp;
|
||||
struct smp_chan *smp = chan->data;
|
||||
struct hci_dev *hdev = hcon->hdev;
|
||||
struct smp_cmd_pairing_confirm cfm;
|
||||
int err;
|
||||
|
||||
|
@ -1936,6 +1990,16 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
|
|||
|
||||
set_bit(SMP_FLAG_REMOTE_PK, &smp->flags);
|
||||
|
||||
smp->method = sc_select_method(smp);
|
||||
|
||||
BT_DBG("%s selected method 0x%02x", hdev->name, smp->method);
|
||||
|
||||
/* JUST_WORKS and JUST_CFM result in an unauthenticated key */
|
||||
if (smp->method == JUST_WORKS || smp->method == JUST_CFM)
|
||||
hcon->pending_sec_level = BT_SECURITY_MEDIUM;
|
||||
else
|
||||
hcon->pending_sec_level = BT_SECURITY_FIPS;
|
||||
|
||||
/* The Initiating device waits for the non-initiating device to
|
||||
* send the confirm value.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue