Commit 4d2d2796 authored by Marcel Holtmann's avatar Marcel Holtmann Committed by Johan Hedberg

Bluetooth: Add support for local OOB data with Secure Connections

For Secure Connections support and the usage of out-of-band pairing,
it is needed to read the P-256 hash and randomizer or P-192 hash and
randomizer. This change will read P-192 data when Secure Connections
is disabled and P-192 and P-256 data when it is enabled.

The difference is between using HCI Read Local OOB Data and using the
new HCI Read Local OOB Extended Data command. The first one has been
introduced with Bluetooth 2.1 and returns only the P-192 data.

< HCI Command: Read Local OOB Data (0x03|0x0057) plen 0
> HCI Event: Command Complete (0x0e) plen 36
      Read Local OOB Data (0x03|0x0057) ncmd 1
        Status: Success (0x00)
        Hash C from P-192: 975a59baa1c4eee391477cb410b23e6d
        Randomizer R with P-192: 9ee63b7dec411d3b467c5ae446df7f7d

The second command has been introduced with Bluetooth 4.1 and will
return P-192 and P-256 data.

< HCI Command: Read Local OOB Extended Data (0x03|0x007d) plen 0
> HCI Event: Command Complete (0x0e) plen 68
      Read Local OOB Extended Data (0x03|0x007d) ncmd 1
        Status: Success (0x00)
        Hash C from P-192: 6489731804b156fa6355efb8124a1389
        Randomizer R with P-192: 4781d5352fb215b2958222b3937b6026
        Hash C from P-256: 69ef8a928b9d07fc149e630e74ecb991
        Randomizer R with P-256: 4781d5352fb215b2958222b3937b6026

The change for the management interface is transparent and no change
is required for existing userspace. The Secure Connections feature
needs to be manually enabled. When it is disabled, then userspace
only gets the P-192 returned and with Secure Connections enabled,
userspace gets P-192 and P-256 in an extended structure.

It is also acceptable to just ignore the P-256 data since it is not
required to support them. The pairing with out-of-band credentials
will still succeed. However then of course no Secure Connection will
b established.
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
Signed-off-by: default avatarJohan Hedberg <johan.hedberg@intel.com>
parent 8e991132
...@@ -1129,8 +1129,9 @@ void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status); ...@@ -1129,8 +1129,9 @@ void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status);
void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
u8 status); u8 status);
void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status); void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status);
void mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
u8 *randomizer, u8 status); u8 *randomizer192, u8 *hash256,
u8 *randomizer256, u8 status);
void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name,
u8 ssp, u8 *eir, u16 eir_len); u8 ssp, u8 *eir, u16 eir_len);
......
...@@ -295,6 +295,12 @@ struct mgmt_rp_read_local_oob_data { ...@@ -295,6 +295,12 @@ struct mgmt_rp_read_local_oob_data {
__u8 hash[16]; __u8 hash[16];
__u8 randomizer[16]; __u8 randomizer[16];
} __packed; } __packed;
struct mgmt_rp_read_local_oob_ext_data {
__u8 hash192[16];
__u8 randomizer192[16];
__u8 hash256[16];
__u8 randomizer256[16];
} __packed;
#define MGMT_OP_ADD_REMOTE_OOB_DATA 0x0021 #define MGMT_OP_ADD_REMOTE_OOB_DATA 0x0021
struct mgmt_cp_add_remote_oob_data { struct mgmt_cp_add_remote_oob_data {
......
...@@ -932,7 +932,7 @@ static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev, ...@@ -932,7 +932,7 @@ static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev,
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev, static void hci_cc_read_local_oob_data(struct hci_dev *hdev,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct hci_rp_read_local_oob_data *rp = (void *) skb->data; struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
...@@ -940,8 +940,22 @@ static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev, ...@@ -940,8 +940,22 @@ static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
hci_dev_lock(hdev); hci_dev_lock(hdev);
mgmt_read_local_oob_data_reply_complete(hdev, rp->hash, mgmt_read_local_oob_data_complete(hdev, rp->hash, rp->randomizer,
rp->randomizer, rp->status); NULL, NULL, rp->status);
hci_dev_unlock(hdev);
}
static void hci_cc_read_local_oob_ext_data(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
hci_dev_lock(hdev);
mgmt_read_local_oob_data_complete(hdev, rp->hash192, rp->randomizer192,
rp->hash256, rp->randomizer256,
rp->status);
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
...@@ -2248,7 +2262,11 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -2248,7 +2262,11 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
break; break;
case HCI_OP_READ_LOCAL_OOB_DATA: case HCI_OP_READ_LOCAL_OOB_DATA:
hci_cc_read_local_oob_data_reply(hdev, skb); hci_cc_read_local_oob_data(hdev, skb);
break;
case HCI_OP_READ_LOCAL_OOB_EXT_DATA:
hci_cc_read_local_oob_ext_data(hdev, skb);
break; break;
case HCI_OP_LE_READ_BUFFER_SIZE: case HCI_OP_LE_READ_BUFFER_SIZE:
......
...@@ -3078,7 +3078,12 @@ static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev, ...@@ -3078,7 +3078,12 @@ static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
goto unlock; goto unlock;
} }
if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_EXT_DATA,
0, NULL);
else
err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL); err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
if (err < 0) if (err < 0)
mgmt_pending_remove(cmd); mgmt_pending_remove(cmd);
...@@ -5077,8 +5082,9 @@ void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status) ...@@ -5077,8 +5082,9 @@ void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
cmd ? cmd->sk : NULL); cmd ? cmd->sk : NULL);
} }
void mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
u8 *randomizer, u8 status) u8 *randomizer192, u8 *hash256,
u8 *randomizer256, u8 status)
{ {
struct pending_cmd *cmd; struct pending_cmd *cmd;
...@@ -5091,14 +5097,33 @@ void mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, ...@@ -5091,14 +5097,33 @@ void mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
if (status) { if (status) {
cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
mgmt_status(status)); mgmt_status(status));
} else {
if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
hash256 && randomizer256) {
struct mgmt_rp_read_local_oob_ext_data rp;
memcpy(rp.hash192, hash192, sizeof(rp.hash192));
memcpy(rp.randomizer192, randomizer192,
sizeof(rp.randomizer192));
memcpy(rp.hash256, hash256, sizeof(rp.hash256));
memcpy(rp.randomizer256, randomizer256,
sizeof(rp.randomizer256));
cmd_complete(cmd->sk, hdev->id,
MGMT_OP_READ_LOCAL_OOB_DATA, 0,
&rp, sizeof(rp));
} else { } else {
struct mgmt_rp_read_local_oob_data rp; struct mgmt_rp_read_local_oob_data rp;
memcpy(rp.hash, hash, sizeof(rp.hash)); memcpy(rp.hash, hash192, sizeof(rp.hash));
memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer)); memcpy(rp.randomizer, randomizer192,
sizeof(rp.randomizer));
cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, cmd_complete(cmd->sk, hdev->id,
0, &rp, sizeof(rp)); MGMT_OP_READ_LOCAL_OOB_DATA, 0,
&rp, sizeof(rp));
}
} }
mgmt_pending_remove(cmd); mgmt_pending_remove(cmd);
......
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