Bluetooth: LE Secure Connections support
Subsystems (2)
cover Bluetooth: LE Secure Connections support
Hi,
First of all, appologies to all for this huge patch set. It's work from the past 6 months or so that wasn't releasable until the 4.2 specification goes public. That happened just some moments ago:
http://www.bluetooth.com/SiteCollectionDocuments/4-2/bluetooth4-2.aspx
I'm sending the patches to the mailing list mainly for reference since Marcel will probably directly merge them from my tree. Any issues/fixes etc should be done on top of them.
Johan
----------------------------------------------------------------
Johan Hedberg (49):
Bluetooth: Add basic SMP defines for LE Secure Connections
Bluetooth: Make auth_req mask dependent on SC enabled or not
Bluetooth: Add SMP flag for SC and set it when necessary.
Bluetooth: Update SMP security level to/from auth_req for SC
Bluetooth: Add mgmt support for LE Secure Connections LTK types
Bluetooth: Set the correct security level for SC LTKs
Bluetooth: Use custom macro for testing BR/EDR SC enabled
Bluetooth: Add mgmt_set_secure_conn support for any LE adapter
Bluetooth: Update LTK lookup to correctly deal with SC LTKs
Bluetooth: Remove unused hci_find_ltk function
Bluetooth: Rename hci_find_ltk_by_addr to hci_find_ltk
Bluetooth: Set link key generation bit if necessary for LE SC
Bluetooth: Add basic support for AES-CMAC
Bluetooth: Add ECC library for LE Secure Connections
Bluetooth: Add basic support for sending our LE SC public key
Bluetooth: Add handler function for receiving LE SC public key
Bluetooth: Add support for sending LE SC Confirm value
Bluetooth: Add LE SC support for responding to Pairing Confirm PDU
Bluetooth: Add support for LE SC numeric comparison
Bluetooth: Add support for handling LE SC user response
Bluetooth: Add support for LE SC DHKey check PDU
Bluetooth: Add support for LE SC key generation
Bluetooth: Track authentication method in SMP context
Bluetooth: Add selection of the SC authentication method
Bluetooth: Detect SMP SC debug keys
Bluetooth: Add check for accidentally generating a debug key
Bluetooth: Set correct LTK type and authentication for SC
Bluetooth: Add support for SC just-works pairing
Bluetooth: Fix BR/EDR Link Key type when derived through LE SC
Bluetooth: Add passkey entry support for LE SC
Bluetooth: Fix DHKey Check sending order for slave role
Bluetooth: Add dummy handler for LE SC keypress notification
Bluetooth: Use debug keys for SMP when HCI_USE_DEBUG_KEYS is set
Bluetooth: Add hci_conn flag for new link key generation
Bluetooth: Add debugfs switch for forcing SMP over BR/EDR
Bluetooth: Add skeleton for BR/EDR SMP channel
Bluetooth: Add full SMP BR/EDR support
Bluetooth: Add SC-only mode support for SMP
Bluetooth: Unify remote OOB data functions
Bluetooth: Store address type with OOB data
Bluetooth: Add support for adding remote OOB data for LE
Bluetooth: Set SMP OOB flag if OOB data is available
Bluetooth: Add basic LE SC OOB support for remote OOB data
Bluetooth: Introduce SMP_DBG macro for low-level debuging
Bluetooth: Fix missing const declarations in SMP functions
Bluetooth: Organize SMP crypto functions to logical sections
Bluetooth: Fix SMP debug key handling
Bluetooth: Fix minor coding style issue in smp.c
Bluetooth: Fix false-positive "uninitialized" compiler warning
include/net/bluetooth/hci.h | 1 + include/net/bluetooth/hci_core.h | 23 +- include/net/bluetooth/l2cap.h | 2 + include/net/bluetooth/mgmt.h | 3 + net/bluetooth/Kconfig | 1 + net/bluetooth/Makefile | 2 +- net/bluetooth/ecc.c | 816 ++++++++++++++++++++ net/bluetooth/ecc.h | 54 ++ net/bluetooth/hci_core.c | 155 ++-- net/bluetooth/hci_event.c | 23 +- net/bluetooth/l2cap_core.c | 4 + net/bluetooth/mgmt.c | 75 +- net/bluetooth/smp.c | 1543 +++++++++++++++++++++++++++++++++---- net/bluetooth/smp.h | 51 +- 14 files changed, 2509 insertions(+), 244 deletions(-)
PATCH 1/49 Bluetooth: Add basic SMP defines for LE Secure Connections
From: Johan Hedberg <[email protected]>
This patch adds basic SMP defines for commands, error codes and PDU definitions for the LE Secure Connections feature.
--- net/bluetooth/smp.h | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-)
net/bluetooth/smp.h +24 -1
@@ -50,10 +50,13 @@ struct smp_cmd_pairing {#define SMP_DIST_ENC_KEY 0x01#define SMP_DIST_ID_KEY 0x02#define SMP_DIST_SIGN 0x04 +#define SMP_DIST_LINK_KEY 0x08#define SMP_AUTH_NONE 0x00#define SMP_AUTH_BONDING 0x01#define SMP_AUTH_MITM 0x04 +#define SMP_AUTH_SC 0x08 +#define SMP_AUTH_KEYPRESS 0x10#define SMP_CMD_PAIRING_CONFIRM 0x03struct smp_cmd_pairing_confirm {
@@ -102,7 +105,23 @@ struct smp_cmd_security_req {__u8 auth_req; } __packed; -#define SMP_CMD_MAX 0x0b +#define SMP_CMD_PUBLIC_KEY 0x0c +struct smp_cmd_public_key { +__u8 x[32 ]; +__u8 y[32 ]; +} __packed; + +#define SMP_CMD_DHKEY_CHECK 0x0d +struct smp_cmd_dhkey_check { +__u8 e[16 ]; +} __packed; + +#define SMP_CMD_KEYPRESS_NOTIFY 0x0e +struct smp_cmd_keypress_notify { +__u8 value; +} __packed; + +#define SMP_CMD_MAX 0x0e#define SMP_PASSKEY_ENTRY_FAILED 0x01#define SMP_OOB_NOT_AVAIL 0x02
@@ -114,6 +133,10 @@ struct smp_cmd_security_req {#define SMP_UNSPECIFIED 0x08#define SMP_REPEATED_ATTEMPTS 0x09#define SMP_INVALID_PARAMS 0x0a +#define SMP_DHKEY_CHECK_FAILED 0x0b +#define SMP_NUMERIC_COMP_FAILED 0x0c +#define SMP_BREDR_PAIRING_IN_PROGRESS 0x0d +#define SMP_CROSS_TRANSP_NOT_ALLOWED 0x0e#define SMP_MIN_ENC_KEY_SIZE 7#define SMP_MAX_ENC_KEY_SIZE 16
Signature · 1 line
2.1.0
PATCH 2/49 Bluetooth: Make auth_req mask dependent on SC enabled or not
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
If we haven't enabled SC support on our side we should use the same mask for the authentication requirement as we were using before SC support was added, otherwise we should use the extended mask for SC.
--- net/bluetooth/smp.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-)
net/bluetooth/smp.c +10 -7
@@ -35,8 +35,9 @@#define SMP_TIMEOUT msecs_to_jiffies(30000) -#define AUTH_REQ_MASK 0x07 -#define KEY_DIST_MASK 0x07 +#define AUTH_REQ_MASK (dev) (test_bit(HCI_SC_ENABLED, &(dev)->dev_flags) ? \ + 0x1f : 0x07) +#define KEY_DIST_MASK 0x07enum {SMP_FLAG_TK_VALID ,
@@ -332,7 +333,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, req->max_key_size =SMP_MAX_ENC_KEY_SIZE ; req->init_key_dist = local_dist; req->resp_key_dist = remote_dist; - req->auth_req = (authreq &AUTH_REQ_MASK ); + req->auth_req = (authreq &AUTH_REQ_MASK (hdev)); smp->remote_key_dist = remote_dist;return ;
@@ -343,7 +344,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, rsp->max_key_size =SMP_MAX_ENC_KEY_SIZE ; rsp->init_key_dist = req->init_key_dist & remote_dist; rsp->resp_key_dist = req->resp_key_dist & local_dist; - rsp->auth_req = (authreq &AUTH_REQ_MASK ); + rsp->auth_req = (authreq &AUTH_REQ_MASK (hdev)); smp->remote_key_dist = rsp->init_key_dist; }
@@ -942,7 +943,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)return SMP_UNSPECIFIED ;/* We didn't start the pairing, so match remote */ - auth = req->auth_req &AUTH_REQ_MASK ; + auth = req->auth_req &AUTH_REQ_MASK (hdev);if (!test_bit (HCI_BONDABLE , &hdev->dev_flags) && (auth &SMP_AUTH_BONDING ))
@@ -997,6 +998,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)struct smp_cmd_pairing *req, *rsp = (void *) skb->data;struct l2cap_chan *chan = conn->smp;struct smp_chan *smp = chan->data; +struct hci_dev *hdev = conn->hcon->hdev;u8 key_size, auth;int ret;
@@ -1016,7 +1018,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)if (check_enc_key_size (conn, key_size))return SMP_ENC_KEY_SIZE ; - auth = rsp->auth_req &AUTH_REQ_MASK ; + auth = rsp->auth_req &AUTH_REQ_MASK (hdev);/* If we need MITM check that it can be achieved */ if (conn->hcon->pending_sec_level >=BT_SECURITY_HIGH ) {
@@ -1151,6 +1153,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)struct smp_cmd_security_req *rp = (void *) skb->data;struct smp_cmd_pairing cp;struct hci_conn *hcon = conn->hcon; +struct hci_dev *hdev = hcon->hdev;struct smp_chan *smp;u8 sec_level, auth;
@@ -1162,7 +1165,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)if (hcon->role !=HCI_ROLE_MASTER )return SMP_CMD_NOTSUPP ; - auth = rp->auth_req &AUTH_REQ_MASK ; + auth = rp->auth_req &AUTH_REQ_MASK (hdev);if (hcon->io_capability ==HCI_IO_NO_INPUT_OUTPUT ) sec_level =BT_SECURITY_MEDIUM ;
Signature · 1 line
2.1.0
PATCH 3/49 Bluetooth: Add SMP flag for SC and set it when necessary.
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
This patch adds a new SMP flag for tracking whether Secure Connections is in use and sets the flag when both remote and local side have elected to use Secure Connections.
--- net/bluetooth/smp.c | 7 +++++++ 1 file changed, 7 insertions(+)
net/bluetooth/smp.c +7 -0
@@ -45,6 +45,7 @@ enum {SMP_FLAG_MITM_AUTH ,SMP_FLAG_COMPLETE ,SMP_FLAG_INITIATOR , + SMP_FLAG_SC, }; struct smp_chan {
@@ -973,6 +974,9 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)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 ;
@@ -1020,6 +1024,9 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) auth = rsp->auth_req &AUTH_REQ_MASK (hdev); +if ((req->auth_req &SMP_AUTH_SC ) && (auth &SMP_AUTH_SC )) +set_bit (SMP_FLAG_SC , &smp->flags); +/* If we need MITM check that it can be achieved */ if (conn->hcon->pending_sec_level >=BT_SECURITY_HIGH ) {u8 method;
Signature · 1 line
2.1.0
PATCH 4/49 Bluetooth: Update SMP security level to/from auth_req for SC
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
This patch updates the functions which map the SMP authentication request to a security level and vice-versa to take into account the Secure Connections feature.
--- net/bluetooth/smp.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)
net/bluetooth/smp.c +14 -4
@@ -284,17 +284,22 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)schedule_delayed_work (&smp->security_timer,SMP_TIMEOUT ); } -static __u8 authreq_to_seclevel (__u8 authreq) +static u8 authreq_to_seclevel (u8 authreq) { -if (authreq &SMP_AUTH_MITM ) -return BT_SECURITY_HIGH ; -else +if (authreq &SMP_AUTH_MITM ) { +if (authreq &SMP_AUTH_SC ) +return BT_SECURITY_FIPS ; +else +return BT_SECURITY_HIGH ; + }else {return BT_SECURITY_MEDIUM ; + } }static __u8 seclevel_to_authreq (__u8 sec_level) {switch (sec_level) { +case BT_SECURITY_FIPS :case BT_SECURITY_HIGH :return SMP_AUTH_MITM |SMP_AUTH_BONDING ;case BT_SECURITY_MEDIUM :
@@ -1026,6 +1031,8 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)if ((req->auth_req &SMP_AUTH_SC ) && (auth &SMP_AUTH_SC ))set_bit (SMP_FLAG_SC , &smp->flags); +else if (conn->hcon->pending_sec_level >BT_SECURITY_HIGH ) + conn->hcon->pending_sec_level =BT_SECURITY_HIGH ;/* If we need MITM check that it can be achieved */ if (conn->hcon->pending_sec_level >=BT_SECURITY_HIGH ) {
@@ -1255,6 +1262,9 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) authreq =seclevel_to_authreq (sec_level); +if (test_bit (HCI_SC_ENABLED , &hcon->hdev->dev_flags)) + authreq |=SMP_AUTH_SC ; +/* Require MITM if IO Capability allows or the security level * requires it. */
Signature · 1 line
2.1.0
PATCH 5/49 Bluetooth: Add mgmt support for LE Secure Connections LTK types
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
We need a dedicated LTK type for LTK resulting from a Secure Connections based SMP pairing. This patch adds a new define for it and ensures that both the New LTK event as well as the Load LTKs command supports it.
--- include/net/bluetooth/mgmt.h | 3 +++ net/bluetooth/mgmt.c | 33 ++++++++++++++++++++++++++------- net/bluetooth/smp.h | 13 +++++++++++++ 3 files changed, 42 insertions(+), 7 deletions(-)
include/net/bluetooth/mgmt.h +3 -0
@@ -184,6 +184,9 @@ struct mgmt_cp_load_link_keys {#define MGMT_LTK_UNAUTHENTICATED 0x00#define MGMT_LTK_AUTHENTICATED 0x01 +#define MGMT_LTK_P256_UNAUTH 0x02 +#define MGMT_LTK_P256_AUTH 0x03 +#define MGMT_LTK_P256_DEBUG 0x04struct mgmt_ltk_info {struct mgmt_addr_info addr;
net/bluetooth/mgmt.c +26 -7
@@ -4910,18 +4910,26 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,else addr_type =ADDR_LE_DEV_RANDOM ; -if (key->master) - type =SMP_LTK ; -else - type =SMP_LTK_SLAVE ; -switch (key->type) {case MGMT_LTK_UNAUTHENTICATED : authenticated =0x00 ; + type = key->master ?SMP_LTK :SMP_LTK_SLAVE ;break ;case MGMT_LTK_AUTHENTICATED : authenticated =0x01 ; + type = key->master ?SMP_LTK :SMP_LTK_SLAVE ; +break ; +case MGMT_LTK_P256_UNAUTH : + authenticated =0x00 ; + type =SMP_LTK_P256 ; +break ; +case MGMT_LTK_P256_AUTH : + authenticated =0x01 ; + type =SMP_LTK_P256 ;break ; +case MGMT_LTK_P256_DEBUG : + authenticated =0x00 ; + type =SMP_LTK_P256_DEBUG ;default :continue ; }
@@ -6101,8 +6109,19 @@ void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,static u8 mgmt_ltk_type (struct smp_ltk *ltk) { -if (ltk->authenticated) -return MGMT_LTK_AUTHENTICATED ; +switch (ltk->type) { +case SMP_LTK : +case SMP_LTK_SLAVE : +if (ltk->authenticated) +return MGMT_LTK_AUTHENTICATED ; +return MGMT_LTK_UNAUTHENTICATED ; +case SMP_LTK_P256 : +if (ltk->authenticated) +return MGMT_LTK_P256_AUTH ; +return MGMT_LTK_P256_UNAUTH ; +case SMP_LTK_P256_DEBUG : +return MGMT_LTK_P256_DEBUG ; + }return MGMT_LTK_UNAUTHENTICATED ; }
net/bluetooth/smp.h +13 -0
@@ -146,8 +146,21 @@ enum {SMP_STK ,SMP_LTK ,SMP_LTK_SLAVE , +SMP_LTK_P256 , + SMP_LTK_P256_DEBUG, }; +static inline bool smp_ltk_is_sc (struct smp_ltk *key) +{ +switch (key->type) { +case SMP_LTK_P256 : +case SMP_LTK_P256_DEBUG : +return true; + } + +return false; +} +static inline u8 smp_ltk_sec_level (struct smp_ltk *key) {if (key->authenticated)
Signature · 1 line
2.1.0
PATCH 6/49 Bluetooth: Set the correct security level for SC LTKs
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
When the looked-up LTK is one generated by Secure Connections pairing the security level it gives is BT_SECURITY_FIPS. This patch updates the LTK request event handler to correctly set this level.
--- net/bluetooth/smp.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
net/bluetooth/smp.h +6 -2
@@ -163,8 +163,12 @@ static inline bool smp_ltk_is_sc(struct smp_ltk *key)static inline u8 smp_ltk_sec_level (struct smp_ltk *key) { -if (key->authenticated) -return BT_SECURITY_HIGH ; +if (key->authenticated) { +if (smp_ltk_is_sc (key)) +return BT_SECURITY_FIPS ; +else +return BT_SECURITY_HIGH ; + }return BT_SECURITY_MEDIUM ; }
Signature · 1 line
2.1.0
PATCH 7/49 Bluetooth: Use custom macro for testing BR/EDR SC enabled
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
Since the HCI_SC_ENABLED flag will also be used for controllers without BR/EDR Secure Connections support whenever we need to check specifically for SC for BR/EDR we also need to check that the controller actually supports it. This patch adds a convenience macro for check all the necessary conditions and converts the places in the code that need it to use it.
--- include/net/bluetooth/hci_core.h | 3 +++ net/bluetooth/hci_core.c | 4 +--- net/bluetooth/hci_event.c | 2 +- net/bluetooth/mgmt.c | 5 ++--- 4 files changed, 7 insertions(+), 7 deletions(-)
include/net/bluetooth/hci_core.h +3 -0
@@ -999,6 +999,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn);#define hdev_is_powered (hdev) (test_bit(HCI_UP, &hdev->flags) && \ !test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) +#define bredr_sc_enabled (dev) ((lmp_sc_capable(dev) || \ + test_bit(HCI_FORCE_SC, &(dev)->dbg_flags)) && \ + test_bit(HCI_SC_ENABLED, &(dev)->dev_flags))/* ----- HCI protocols ----- */ #define HCI_PROTO_DEFER 0x01
net/bluetooth/hci_core.c +1 -3
@@ -1734,9 +1734,7 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt)hci_req_add (req,HCI_OP_READ_SYNC_TRAIN_PARAMS ,0 ,NULL );/* Enable Secure Connections if supported and configured */ -if ((lmp_sc_capable (hdev) || -test_bit (HCI_FORCE_SC , &hdev->dbg_flags)) && -test_bit (HCI_SC_ENABLED , &hdev->dev_flags)) { +if (bredr_sc_enabled (hdev)) {u8 support =0x01 ;hci_req_add (req,HCI_OP_WRITE_SC_SUPPORT ,sizeof (support), &support);
net/bluetooth/hci_event.c +1 -1
@@ -4027,7 +4027,7 @@ static void hci_remote_oob_data_request_evt(struct hci_dev *hdev, data =hci_find_remote_oob_data (hdev, &ev->bdaddr);if (data) { -if (test_bit (HCI_SC_ENABLED , &hdev->dev_flags)) { +if (bredr_sc_enabled (hdev)) {struct hci_cp_remote_oob_ext_data_reply cp;bacpy (&cp.bdaddr, &ev->bdaddr);
net/bluetooth/mgmt.c +2 -3
@@ -3562,7 +3562,7 @@ static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev, goto unlock; } -if (test_bit (HCI_SC_ENABLED , &hdev->dev_flags)) +if (bredr_sc_enabled (hdev)) err =hci_send_cmd (hdev,HCI_OP_READ_LOCAL_OOB_EXT_DATA ,0 ,NULL );else
@@ -6803,8 +6803,7 @@ void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,cmd_status (cmd->sk, hdev->id,MGMT_OP_READ_LOCAL_OOB_DATA ,mgmt_status (status)); }else { -if (test_bit (HCI_SC_ENABLED , &hdev->dev_flags) && - hash256 && rand256) { +if (bredr_sc_enabled (hdev) && hash256 && rand256) {struct mgmt_rp_read_local_oob_ext_data rp;memcpy (rp.hash192, hash192,sizeof (rp.hash192));
Signature · 1 line
2.1.0
PATCH 8/49 Bluetooth: Add mgmt_set_secure_conn support for any LE adapter
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
Since LE Secure Connections is a purely host-side feature we should offer the Secure Connections mgmt setting for any adapter with LE support. This patch updates the supported settings value and the set_secure_conn command handler accordingly.
--- net/bluetooth/mgmt.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-)
net/bluetooth/mgmt.c +8 -9
@@ -574,6 +574,7 @@ static u32 get_supported_settings(struct hci_dev *hdev)if (lmp_le_capable (hdev)) { settings |=MGMT_SETTING_LE ; settings |=MGMT_SETTING_ADVERTISING ; + settings |=MGMT_SETTING_SECURE_CONN ; settings |=MGMT_SETTING_PRIVACY ; }
@@ -4572,18 +4573,13 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev, {struct mgmt_mode *cp = data;struct pending_cmd *cmd; -u8 val, status; +u8 val;int err;BT_DBG ("request for %s" , hdev->name); - status =mgmt_bredr_support (hdev); -if (status) -return cmd_status (sk, hdev->id,MGMT_OP_SET_SECURE_CONN , - status); - -if (!lmp_sc_capable (hdev) && - !test_bit (HCI_FORCE_SC , &hdev->dbg_flags)) +if (!test_bit (HCI_LE_ENABLED , &hdev->dev_flags) && + !lmp_sc_capable (hdev) && !test_bit (HCI_FORCE_SC , &hdev->dbg_flags))return cmd_status (sk, hdev->id,MGMT_OP_SET_SECURE_CONN ,MGMT_STATUS_NOT_SUPPORTED );
@@ -4593,7 +4589,10 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,hci_dev_lock (hdev); -if (!hdev_is_powered (hdev)) { +if (!hdev_is_powered (hdev) || + (!lmp_sc_capable (hdev) && + !test_bit (HCI_FORCE_SC , &hdev->dbg_flags)) || + !test_bit (HCI_BREDR_ENABLED , &hdev->dev_flags)) {bool changed;if (cp->val) {
Signature · 1 line
2.1.0
PATCH 9/49 Bluetooth: Update LTK lookup to correctly deal with SC LTKs
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
LTKs derived from Secure Connections based pairing are symmetric, i.e. they should match both master and slave role. This patch updates the LTK lookup functions to ignore the desired role when dealing with SC LTKs.
Furthermore, with Secure Connections the EDiv and Rand values are not used and should always be set to zero. This patch updates the LTK lookup to first use the bdaddr as key and then do the necessary verifications of EDiv and Rand based on whether the found LTK is for SC or not.
--- net/bluetooth/hci_core.c | 30 +++++++++++++++++++++++------- net/bluetooth/hci_event.c | 15 +++++++++++++-- 2 files changed, 36 insertions(+), 9 deletions(-)
net/bluetooth/hci_core.c +23 -7
@@ -3195,11 +3195,18 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand,if (k->ediv != ediv || k->rand != rand)continue ; -if (ltk_role (k->type) != role) -continue ; +if (smp_ltk_is_sc (k)) { +if (k->type ==SMP_LTK_P256_DEBUG && + !test_bit (HCI_KEEP_DEBUG_KEYS , &hdev->dev_flags)) +continue ; +rcu_read_unlock (); +return k; + } -rcu_read_unlock (); -return k; +if (ltk_role (k->type) == role) { +rcu_read_unlock (); +return k; + } }rcu_read_unlock ();
@@ -3213,9 +3220,18 @@ struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,rcu_read_lock ();list_for_each_entry_rcu (k, &hdev->long_term_keys, list) { -if (addr_type == k->bdaddr_type && -bacmp (bdaddr, &k->bdaddr) ==0 && -ltk_role (k->type) == role) { +if (addr_type != k->bdaddr_type ||bacmp (bdaddr, &k->bdaddr)) +continue ; + +if (smp_ltk_is_sc (k)) { +if (k->type ==SMP_LTK_P256_DEBUG && + !test_bit (HCI_KEEP_DEBUG_KEYS , &hdev->dev_flags)) +continue ; +rcu_read_unlock (); +return k; + } + +if (ltk_role (k->type) == role) {rcu_read_unlock ();return k; }
net/bluetooth/hci_event.c +13 -2
@@ -4590,10 +4590,21 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)if (conn ==NULL ) goto not_found; - ltk =hci_find_ltk (hdev, ev->ediv, ev->rand, conn->role); -if (ltk ==NULL ) + ltk =hci_find_ltk_by_addr (hdev, &conn->dst, conn->dst_type, + conn->role); +if (!ltk) goto not_found; +if (smp_ltk_is_sc (ltk)) { +/* With SC both EDiv and Rand are set to zero */ +if (ev->ediv || ev->rand) + goto not_found; + }else { +/* For non-SC keys check that EDiv and Rand match */ +if (ev->ediv != ltk->ediv || ev->rand != ltk->rand) + goto not_found; + } +memcpy (cp.ltk, ltk->val,sizeof (ltk->val)); cp.handle =cpu_to_le16 (conn->handle);
Signature · 1 line
2.1.0
PATCH 10/49 Bluetooth: Remove unused hci_find_ltk function
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
Now that LTKs are always looked up based on bdaddr (with EDiv/Rand checks done after a successful lookup) the hci_find_ltk function is not needed anymore. This patch removes the function.
--- include/net/bluetooth/hci_core.h | 2 -- net/bluetooth/hci_core.c | 28 ---------------------------- 2 files changed, 30 deletions(-)
include/net/bluetooth/hci_core.h +0 -2
@@ -921,8 +921,6 @@ struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);struct link_key *hci_add_link_key (struct hci_dev *hdev,struct hci_conn *conn,bdaddr_t *bdaddr,u8 *val,u8 type,u8 pin_len,bool *persistent); -struct smp_ltk *hci_find_ltk (struct hci_dev *hdev,__le16 ediv,__le64 rand, -u8 role);struct smp_ltk *hci_add_ltk (struct hci_dev *hdev,bdaddr_t *bdaddr,u8 addr_type,u8 type,u8 authenticated,u8 tk[16 ],u8 enc_size,__le16 ediv,__le64 rand);
net/bluetooth/hci_core.c +0 -28
@@ -3185,34 +3185,6 @@ static u8 ltk_role(u8 type)return HCI_ROLE_SLAVE ; } -struct smp_ltk *hci_find_ltk (struct hci_dev *hdev,__le16 ediv,__le64 rand, -u8 role) -{ -struct smp_ltk *k; - -rcu_read_lock (); -list_for_each_entry_rcu (k, &hdev->long_term_keys, list) { -if (k->ediv != ediv || k->rand != rand) -continue ; - -if (smp_ltk_is_sc (k)) { -if (k->type ==SMP_LTK_P256_DEBUG && - !test_bit (HCI_KEEP_DEBUG_KEYS , &hdev->dev_flags)) -continue ; -rcu_read_unlock (); -return k; - } - -if (ltk_role (k->type) == role) { -rcu_read_unlock (); -return k; - } - } -rcu_read_unlock (); - -return NULL ; -} -struct smp_ltk *hci_find_ltk_by_addr (struct hci_dev *hdev,bdaddr_t *bdaddr,u8 addr_type,u8 role) {
Signature · 1 line
2.1.0
PATCH 11/49 Bluetooth: Rename hci_find_ltk_by_addr to hci_find_ltk
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
Now that hci_find_ltk_by_addr is the only LTK lookup function there's no need to keep the long name anymore. This patch shortens the function name to simply hci_find_ltk.
--- include/net/bluetooth/hci_core.h | 4 ++-- net/bluetooth/hci_core.c | 6 +++--- net/bluetooth/hci_event.c | 3 +-- net/bluetooth/smp.c | 6 ++---- 4 files changed, 8 insertions(+), 11 deletions(-)
include/net/bluetooth/hci_core.h +2 -2
@@ -924,8 +924,8 @@ struct link_key *hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn,struct smp_ltk *hci_add_ltk (struct hci_dev *hdev,bdaddr_t *bdaddr,u8 addr_type,u8 type,u8 authenticated,u8 tk[16 ],u8 enc_size,__le16 ediv,__le64 rand); -struct smp_ltk *hci_find_ltk_by_addr (struct hci_dev *hdev,bdaddr_t *bdaddr, -u8 addr_type,u8 role); +struct smp_ltk *hci_find_ltk (struct hci_dev *hdev,bdaddr_t *bdaddr, +u8 addr_type,u8 role);int hci_remove_ltk (struct hci_dev *hdev,bdaddr_t *bdaddr,u8 bdaddr_type);void hci_smp_ltks_clear (struct hci_dev *hdev);int hci_remove_link_key (struct hci_dev *hdev,bdaddr_t *bdaddr);
net/bluetooth/hci_core.c +3 -3
@@ -3185,8 +3185,8 @@ static u8 ltk_role(u8 type)return HCI_ROLE_SLAVE ; } -struct smp_ltk *hci_find_ltk_by_addr (struct hci_dev *hdev,bdaddr_t *bdaddr, -u8 addr_type,u8 role) +struct smp_ltk *hci_find_ltk (struct hci_dev *hdev,bdaddr_t *bdaddr, +u8 addr_type,u8 role) {struct smp_ltk *k;
@@ -3313,7 +3313,7 @@ struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr,struct smp_ltk *key, *old_key;u8 role =ltk_role (type); - old_key =hci_find_ltk_by_addr (hdev, bdaddr, addr_type, role); + old_key =hci_find_ltk (hdev, bdaddr, addr_type, role);if (old_key) key = old_key;else {
net/bluetooth/hci_event.c +1 -2
@@ -4590,8 +4590,7 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)if (conn ==NULL ) goto not_found; - ltk =hci_find_ltk_by_addr (hdev, &conn->dst, conn->dst_type, - conn->role); + ltk =hci_find_ltk (hdev, &conn->dst, conn->dst_type, conn->role);if (!ltk) goto not_found;
net/bluetooth/smp.c +2 -4
@@ -1118,8 +1118,7 @@ static bool smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level)struct smp_ltk *key;struct hci_conn *hcon = conn->hcon; - key =hci_find_ltk_by_addr (hcon->hdev, &hcon->dst, hcon->dst_type, - hcon->role); + key =hci_find_ltk (hcon->hdev, &hcon->dst, hcon->dst_type, hcon->role);if (!key)return false;
@@ -1152,8 +1151,7 @@ bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level,*/ if (key_pref ==SMP_USE_LTK &&test_bit (HCI_CONN_STK_ENCRYPT , &hcon->flags) && -hci_find_ltk_by_addr (hcon->hdev, &hcon->dst, hcon->dst_type, - hcon->role)) +hci_find_ltk (hcon->hdev, &hcon->dst, hcon->dst_type, hcon->role))return false;if (hcon->sec_level >= sec_level)
Signature · 1 line
2.1.0
PATCH 12/49 Bluetooth: Set link key generation bit if necessary for LE SC
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
Depending on whether Secure Connections is enabled or not we may need to add the link key generation bit to the key distribution. This patch does the necessary modifications to the build_pairing_cmd() function.
--- net/bluetooth/smp.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
net/bluetooth/smp.c +10 -0
@@ -333,6 +333,16 @@ static void build_pairing_cmd(struct l2cap_conn *conn,if (test_bit (HCI_PRIVACY , &hdev->dev_flags)) local_dist |=SMP_DIST_ID_KEY ; +if (test_bit (HCI_SC_ENABLED , &hdev->dev_flags)) { +if ((authreq &SMP_AUTH_SC ) && +test_bit (HCI_SSP_ENABLED , &hdev->dev_flags)) { + local_dist |=SMP_DIST_LINK_KEY ; + remote_dist |=SMP_DIST_LINK_KEY ; + } + }else { + authreq &= ~SMP_AUTH_SC ; + } +if (rsp ==NULL ) { req->io_capability = conn->hcon->io_capability; req->oob_flag =SMP_OOB_NOT_PRESENT ;
Signature · 1 line
2.1.0
PATCH 13/49 Bluetooth: Add basic support for AES-CMAC
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
Most of the LE Secure Connections SMP crypto functions build on top of the AES-CMAC function. This patch adds access to AES-CMAC in the kernel crypto subsystem by allocating a crypto_hash handle for it in a similar way that we have one for AES-CBC.
--- net/bluetooth/Kconfig | 1 + net/bluetooth/smp.c | 10 ++++++++++ 2 files changed, 11 insertions(+)
net/bluetooth/Kconfig +1 -0
@@ -10,6 +10,7 @@ menuconfig BT select CRYPTO select CRYPTO_BLKCIPHER select CRYPTO_AES + select CRYPTO_CMAC select CRYPTO_ECB select CRYPTO_SHA256 help
net/bluetooth/smp.c +10 -0
@@ -72,6 +72,7 @@ struct smp_chan {unsigned long flags;struct crypto_blkcipher *tfm_aes; +struct crypto_hash *tfm_cmac; };static inline void swap_buf (const u8 *src,u8 *dst,size_t len)
@@ -396,6 +397,7 @@ static void smp_chan_destroy(struct l2cap_conn *conn)kfree (smp->slave_csrk);crypto_free_blkcipher (smp->tfm_aes); +crypto_free_hash (smp->tfm_cmac);/* If pairing failed clean up any keys we might have */ if (!complete) {
@@ -861,6 +863,14 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)return NULL ; } + smp->tfm_cmac =crypto_alloc_hash ("cmac(aes)" ,0 ,CRYPTO_ALG_ASYNC ); +if (IS_ERR (smp->tfm_cmac)) { +BT_ERR ("Unable to create CMAC crypto context" ); +crypto_free_blkcipher (smp->tfm_aes); +kfree (smp); +return NULL ; + } + smp->conn = conn; chan->data = smp;
Signature · 1 line
2.1.0
PATCH 14/49 Bluetooth: Add ECC library for LE Secure Connections
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
This patch adds a simple ECC library that will act as a fundamental building block for LE Secure Connections. The library has a simple API consisting of two functions: one for generating a public/private key pair and another one for generating a Diffie-Hellman key from a local private key and a remote public key.
The code has been taken from https://github.com/kmackay/easy-ecc and modified to conform with the kernel coding style.
--- net/bluetooth/Makefile | 2 +- net/bluetooth/ecc.c | 816 +++++++++++++++++++++++++++++++++++++++++++++++++ net/bluetooth/ecc.h | 54 ++++ 3 files changed, 871 insertions(+), 1 deletion(-) create mode 100644 net/bluetooth/ecc.c create mode 100644 net/bluetooth/ecc.h
net/bluetooth/Makefile +1 -1
@@ -13,6 +13,6 @@ bluetooth_6lowpan-y := 6lowpan.o bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \ hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \ - a2mp.o amp.o + a2mp.o amp.o ecc.o subdir-ccflags-y += -D__CHECK_ENDIAN__
net/bluetooth/ecc.c new file +816 -0
816 lines not on this page · raw message
net/bluetooth/ecc.h new file +54 -0
54 lines not on this page · raw message
Signature · 1 line
2.1.0
PATCH 15/49 Bluetooth: Add basic support for sending our LE SC public key
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
When the initial pairing request & response PDUs have been exchanged and both have had the LE SC bit set the next step is to generate a ECDH key pair and to send the public key to the remote side. This patch adds basic support for generating the key pair and sending the public key using the new Public Key SMP PDU. It is the initiating device that sends the public key first and the non-initiating device responds by sending its public key respectively (in a subsequent patch).
--- net/bluetooth/smp.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-)
net/bluetooth/smp.c +44 -1
@@ -29,10 +29,14 @@#include <net/bluetooth/l2cap.h> #include <net/bluetooth/mgmt.h> +#include "ecc.h" #include "smp.h" #define SMP_ALLOW_CMD (smp, code) set_bit(code, &smp->allow_cmd) +/* Keys which are not distributed with Secure Connections */ +#define SMP_SC_NO_DIST (SMP_DIST_ENC_KEY | SMP_DIST_LINK_KEY); +#define SMP_TIMEOUT msecs_to_jiffies(30000)#define AUTH_REQ_MASK (dev) (test_bit(HCI_SC_ENABLED, &(dev)->dev_flags) ? \
@@ -71,6 +75,10 @@ struct smp_chan {struct smp_irk *remote_irk;unsigned long flags; +/* Secure Connections variables */ +u8 local_pk[64 ]; +u8 local_sk[32 ]; +struct crypto_blkcipher *tfm_aes;struct crypto_hash *tfm_cmac; };
@@ -1012,7 +1020,18 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)memcpy (&smp->prsp[1 ], &rsp,sizeof (rsp));smp_send_cmd (conn,SMP_CMD_PAIRING_RSP ,sizeof (rsp), &rsp); -SMP_ALLOW_CMD (smp,SMP_CMD_PAIRING_CONFIRM ); + +clear_bit (SMP_FLAG_INITIATOR , &smp->flags); + +if (test_bit (SMP_FLAG_SC , &smp->flags)) { +SMP_ALLOW_CMD (smp,SMP_CMD_PUBLIC_KEY ); +/* Clear bits which are generated but not distributed */ + smp->remote_key_dist &= ~SMP_SC_NO_DIST ; +/* Wait for Public Key from Initiating Device */ +return 0 ; + }else { +SMP_ALLOW_CMD (smp,SMP_CMD_PAIRING_CONFIRM ); + }/* Request setup of TK */ ret =tk_request (conn,0 , auth, rsp.io_capability, req->io_capability);
@@ -1022,6 +1041,23 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)return 0 ; } +static u8 sc_send_public_key (struct smp_chan *smp) +{ +BT_DBG ("" ); + +/* Generate local key pair for Secure Connections */ +if (!ecc_make_key (smp->local_pk, smp->local_sk)) +return SMP_UNSPECIFIED ; + +BT_DBG ("Local Public Key X: %32phN" , smp->local_pk); +BT_DBG ("Local Public Key Y: %32phN" , &smp->local_pk[32 ]); +BT_DBG ("Local Private Key: %32phN" , smp->local_sk); + +smp_send_cmd (smp->conn,SMP_CMD_PUBLIC_KEY ,64 , smp->local_pk); + +return 0 ; +} +static u8 smp_cmd_pairing_rsp (struct l2cap_conn *conn,struct sk_buff *skb) {struct smp_cmd_pairing *req, *rsp = (void *) skb->data;
@@ -1074,6 +1110,13 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)*/ smp->remote_key_dist &= rsp->resp_key_dist; +if (test_bit (SMP_FLAG_SC , &smp->flags)) { +/* Clear bits which are generated but not distributed */ + smp->remote_key_dist &= ~SMP_SC_NO_DIST ; +SMP_ALLOW_CMD (smp,SMP_CMD_PUBLIC_KEY ); +return sc_send_public_key (smp); + } + auth |= req->auth_req; ret =tk_request (conn,0 , auth, req->io_capability, rsp->io_capability);
Signature · 1 line
2.1.0
PATCH 16/49 Bluetooth: Add handler function for receiving LE SC public key
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
This patch adds a handler function for the LE SC SMP Public Key PDU. When we receive the key we proceed with generating the shared DHKey value from the remote public key and local private key.
--- net/bluetooth/smp.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+)
net/bluetooth/smp.c +44 -0
@@ -50,6 +50,7 @@ enum {SMP_FLAG_COMPLETE ,SMP_FLAG_INITIATOR ,SMP_FLAG_SC , + SMP_FLAG_REMOTE_PK, }; struct smp_chan {
@@ -78,6 +79,8 @@ struct smp_chan {/* Secure Connections variables */ u8 local_pk[64 ];u8 local_sk[32 ]; +u8 remote_pk[64 ]; +u8 dhkey[32 ];struct crypto_blkcipher *tfm_aes;struct crypto_hash *tfm_cmac;
@@ -1513,6 +1516,43 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb)return 0 ; } +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; +int err; + +BT_DBG ("conn %p" , conn); + +if (skb->len <sizeof (*key)) +return SMP_INVALID_PARAMS ; + +memcpy (smp->remote_pk, key,64 ); + +/* Non-initiating device sends its public key after receiving +* the key from the initiating device. +*/ +if (!hcon->out) { + err =sc_send_public_key (smp); +if (err) +return err; + } + +BT_DBG ("Remote Public Key X: %32phN" , smp->remote_pk); +BT_DBG ("Remote Public Key Y: %32phN" , &smp->remote_pk[32 ]); + +if (!ecdh_shared_secret (smp->remote_pk, smp->local_sk, smp->dhkey)) +return SMP_UNSPECIFIED ; + +BT_DBG ("DHKey %32phN" , smp->dhkey); + +set_bit (SMP_FLAG_REMOTE_PK , &smp->flags); + +return 0 ; +} +static int smp_sig_channel (struct l2cap_chan *chan,struct sk_buff *skb) {struct l2cap_conn *conn = chan->conn;
@@ -1597,6 +1637,10 @@ static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb) reason =smp_cmd_sign_info (conn, skb);break ; +case SMP_CMD_PUBLIC_KEY : + reason =smp_cmd_public_key (conn, skb); +break ; +default :BT_DBG ("Unknown command code 0x%2.2x" , code); reason =SMP_CMD_NOTSUPP ;
Signature · 1 line
2.1.0
PATCH 17/49 Bluetooth: Add support for sending LE SC Confirm value
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
Once the public key exchange is complete the next step is for the non-initiating device to send a SMP Pairing Confirm PDU to the initiating device. This requires the use of a new smp_f4 confirm value generation function which in turn builds on the AES-CMAC cryptographic function.
--- net/bluetooth/smp.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+)
net/bluetooth/smp.c +96 -0
@@ -43,6 +43,9 @@ 0x1f : 0x07)#define KEY_DIST_MASK 0x07 +/* Maximum message length that can be passed to aes_cmac */ +#define CMAC_MSG_MAX 80 +enum {SMP_FLAG_TK_VALID ,SMP_FLAG_CFM_PENDING ,
@@ -94,6 +97,84 @@ static inline void swap_buf(const u8 *src, u8 *dst, size_t len) dst[len -1 - i] = src[i]; } +static int aes_cmac (struct crypto_hash *tfm,const u8 k[16 ],const u8 *m, +size_t len,u8 mac[16 ]) +{ +uint8_t tmp[16 ], mac_msb[16 ], msg_msb[CMAC_MSG_MAX ]; +struct hash_desc desc; +struct scatterlist sg; +int err; + +if (len >CMAC_MSG_MAX ) +return -EFBIG ; + +if (!tfm) { +BT_ERR ("tfm %p" , tfm); +return -EINVAL ; + } + + desc.tfm = tfm; + desc.flags =0 ; + +crypto_hash_init (&desc); + +/* Swap key and message from LSB to MSB */ +swap_buf (k, tmp,16 ); +swap_buf (m, msg_msb, len); + +BT_DBG ("msg (len %zu) %*phN" , len, len, m); +BT_DBG ("key %16phN" , k); + + err =crypto_hash_setkey (tfm, tmp,16 ); +if (err) { +BT_ERR ("cipher setkey failed: %d" , err); +return err; + } + +sg_init_one (&sg, msg_msb, len); + + err =crypto_hash_update (&desc, &sg, len); +if (err) { +BT_ERR ("Hash update error %d" , err); +return err; + } + + err =crypto_hash_final (&desc, mac_msb); +if (err) { +BT_ERR ("Hash final error %d" , err); +return err; + } + +swap_buf (mac_msb, mac,16 ); + +BT_DBG ("mac %16phN" , mac); + +return 0 ; +} + +static int smp_f4 (struct crypto_hash *tfm_cmac,const u8 u[32 ],const u8 v[32 ], +const u8 x[16 ],u8 z,u8 res[16 ]) +{ +u8 m[65 ]; +int err; + +BT_DBG ("u %32phN" , u); +BT_DBG ("v %32phN" , v); +BT_DBG ("x %16phN z %02x" , x, z); + + m[0 ] = z; +memcpy (m +1 , v,32 ); +memcpy (m +33 , u,32 ); + + err =aes_cmac (tfm_cmac, x, m,sizeof (m), res); +if (err) +return err; + +BT_DBG ("res %16phN" , res); + +return err; +} +static int smp_e (struct crypto_blkcipher *tfm,const u8 *k,u8 *r) {struct blkcipher_desc desc;
@@ -1522,6 +1603,7 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)struct hci_conn *hcon = conn->hcon;struct l2cap_chan *chan = conn->smp;struct smp_chan *smp = chan->data; +struct smp_cmd_pairing_confirm cfm;int err;BT_DBG ("conn %p" , conn);
@@ -1550,6 +1632,20 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)set_bit (SMP_FLAG_REMOTE_PK , &smp->flags); +/* The Initiating device waits for the non-initiating device to +* send the confirm value. +*/ +if (conn->hcon->out) +return 0 ; + + err =smp_f4 (smp->tfm_cmac, smp->local_pk, smp->remote_pk, smp->prnd, +0 , cfm.confirm_val); +if (err) +return SMP_UNSPECIFIED ; + +smp_send_cmd (conn,SMP_CMD_PAIRING_CONFIRM ,sizeof (cfm), &cfm); +SMP_ALLOW_CMD (smp,SMP_CMD_PAIRING_RANDOM ); +return 0 ; }
Signature · 1 line
2.1.0
PATCH 18/49 Bluetooth: Add LE SC support for responding to Pairing Confirm PDU
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
When LE SC is being used we should always respond to it by sending our local random number. This patch adds a convenience function for it which also contains a check for the pre-requisite public key exchange completion
--- net/bluetooth/smp.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
net/bluetooth/smp.c +22 -0
@@ -1216,6 +1216,25 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)return 0 ; } +static u8 sc_check_confirm (struct smp_chan *smp) +{ +struct l2cap_conn *conn = smp->conn; + +BT_DBG ("" ); + +/* Public Key exchange must happen before any other steps */ +if (!test_bit (SMP_FLAG_REMOTE_PK , &smp->flags)) +return SMP_UNSPECIFIED ; + +if (conn->hcon->out) { +smp_send_cmd (conn,SMP_CMD_PAIRING_RANDOM ,sizeof (smp->prnd), + smp->prnd); +SMP_ALLOW_CMD (smp,SMP_CMD_PAIRING_RANDOM ); + } + +return 0 ; +} +static u8 smp_cmd_pairing_confirm (struct l2cap_conn *conn,struct sk_buff *skb) {struct l2cap_chan *chan = conn->smp;
@@ -1229,6 +1248,9 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)memcpy (smp->pcnf, skb->data,sizeof (smp->pcnf));skb_pull (skb,sizeof (smp->pcnf)); +if (test_bit (SMP_FLAG_SC , &smp->flags)) +return sc_check_confirm (smp); +if (conn->hcon->out) {smp_send_cmd (conn,SMP_CMD_PAIRING_RANDOM ,sizeof (smp->prnd), smp->prnd);
Signature · 1 line
2.1.0
PATCH 19/49 Bluetooth: Add support for LE SC numeric comparison
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
After the Pairing Confirm and Random PDUs have been exchanged in LE SC it's time to generate a numeric comparison value using a new smp_g2 cryptographic function (which also builds on AES-CMAC). This patch adds the smp_g2 implementation and updates the Pairing Random PDU handler to proceed with the value genration and user confirmation.
--- net/bluetooth/smp.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-)
net/bluetooth/smp.c +70 -1
@@ -175,6 +175,32 @@ static int smp_f4(struct crypto_hash *tfm_cmac, const u8 u[32], const u8 v[32],return err; } +static int smp_g2 (struct crypto_hash *tfm_cmac,const u8 u[32 ],const u8 v[32 ], +const u8 x[16 ],const u8 y[16 ],u32 *val) +{ +u8 m[80 ], tmp[16 ]; +int err; + +BT_DBG ("u %32phN" , u); +BT_DBG ("v %32phN" , v); +BT_DBG ("x %16phN y %16phN" , x, y); + +memcpy (m, y,16 ); +memcpy (m +16 , v,32 ); +memcpy (m +48 , u,32 ); + + err =aes_cmac (tfm_cmac, x, m,sizeof (m), tmp); +if (err) +return err; + + *val =get_unaligned_le32 (tmp); + *val %=1000000 ; + +BT_DBG ("val %06u" , *val); + +return 0 ; +} +static int smp_e (struct crypto_blkcipher *tfm,const u8 *k,u8 *r) {struct blkcipher_desc desc;
@@ -1270,6 +1296,10 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) {struct l2cap_chan *chan = conn->smp;struct smp_chan *smp = chan->data; +struct hci_conn *hcon = conn->hcon; +u8 *pkax, *pkbx, *na, *nb; +u32 passkey; +int err;BT_DBG ("conn %p" , conn);
@@ -1279,7 +1309,46 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)memcpy (smp->rrnd, skb->data,sizeof (smp->rrnd));skb_pull (skb,sizeof (smp->rrnd)); -return smp_random (smp); +if (!test_bit (SMP_FLAG_SC , &smp->flags)) +return smp_random (smp); + +if (hcon->out) { +u8 cfm[16 ]; + + err =smp_f4 (smp->tfm_cmac, smp->remote_pk, smp->local_pk, + smp->rrnd,0 , cfm); +if (err) +return SMP_UNSPECIFIED ; + +if (memcmp (smp->pcnf, cfm,16 )) +return SMP_CONFIRM_FAILED ; + + pkax = smp->local_pk; + pkbx = smp->remote_pk; + na = smp->prnd; + nb = smp->rrnd; + }else { +smp_send_cmd (conn,SMP_CMD_PAIRING_RANDOM ,sizeof (smp->prnd), + smp->prnd); +SMP_ALLOW_CMD (smp,SMP_CMD_DHKEY_CHECK ); + + pkax = smp->remote_pk; + pkbx = smp->local_pk; + na = smp->rrnd; + nb = smp->prnd; + } + + err =smp_g2 (smp->tfm_cmac, pkax, pkbx, na, nb, &passkey); +if (err) +return SMP_UNSPECIFIED ; + + err =mgmt_user_confirm_request (hcon->hdev, &hcon->dst, + hcon->type, hcon->dst_type, + passkey,0 ); +if (err) +return SMP_UNSPECIFIED ; + +return 0 ; }static bool smp_ltk_encrypt (struct l2cap_conn *conn,u8 sec_level)
Signature · 1 line
2.1.0
PATCH 20/49 Bluetooth: Add support for handling LE SC user response
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
With LE SC, once the user has responded to the numeric comparison it's time to send DHKey check values in both directions. The DHKey check value is generated using new smp_f5 and smp_f6 cryptographic functions. The smp_f5 function is responsible for generating the LTK and the MacKey values whereas the smp_f6 function takes the MacKey as input and generates the DHKey Check value.
--- net/bluetooth/smp.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+)
net/bluetooth/smp.c +154 -0
@@ -84,6 +84,7 @@ struct smp_chan {u8 local_sk[32 ];u8 remote_pk[64 ];u8 dhkey[32 ]; +u8 mackey[16 ];struct crypto_blkcipher *tfm_aes;struct crypto_hash *tfm_cmac;
@@ -175,6 +176,86 @@ static int smp_f4(struct crypto_hash *tfm_cmac, const u8 u[32], const u8 v[32],return err; } +static int smp_f5 (struct crypto_hash *tfm_cmac,u8 w[32 ],u8 n1[16 ],u8 n2[16 ], +u8 a1[7 ],u8 a2[7 ],u8 mackey[16 ],u8 ltk[16 ]) +{ +/* The btle, salt and length "magic" values are as defined in +* the SMP section of the Bluetooth core specification. In ASCII +* the btle value ends up being 'btle'. The salt is just a +* random number whereas length is the value 256 in little +* endian format. +*/ +const u8 btle[4 ] = {0x65 ,0x6c ,0x74 ,0x62 }; +const u8 salt[16 ] = {0xbe ,0x83 ,0x60 ,0x5a ,0xdb ,0x0b ,0x37 ,0x60 , +0x38 ,0xa5 ,0xf5 ,0xaa ,0x91 ,0x83 ,0x88 ,0x6c }; +const u8 length[2 ] = {0x00 ,0x01 }; +u8 m[53 ], t[16 ]; +int err; + +BT_DBG ("w %32phN" , w); +BT_DBG ("n1 %16phN n2 %16phN" , n1, n2); +BT_DBG ("a1 %7phN a2 %7phN" , a1, a2); + + err =aes_cmac (tfm_cmac, salt, w,32 , t); +if (err) +return err; + +BT_DBG ("t %16phN" , t); + +memcpy (m, length,2 ); +memcpy (m +2 , a2,7 ); +memcpy (m +9 , a1,7 ); +memcpy (m +16 , n2,16 ); +memcpy (m +32 , n1,16 ); +memcpy (m +48 , btle,4 ); + + m[52 ] =0 ;/* Counter */ + + err =aes_cmac (tfm_cmac, t, m,sizeof (m), mackey); +if (err) +return err; + +BT_DBG ("mackey %16phN" , mackey); + + m[52 ] =1 ;/* Counter */ + + err =aes_cmac (tfm_cmac, t, m,sizeof (m), ltk); +if (err) +return err; + +BT_DBG ("ltk %16phN" , ltk); + +return 0 ; +} + +static int smp_f6 (struct crypto_hash *tfm_cmac,const u8 w[16 ], +const u8 n1[16 ],u8 n2[16 ],const u8 r[16 ], +const u8 io_cap[3 ],const u8 a1[7 ],const u8 a2[7 ], +u8 res[16 ]) +{ +u8 m[65 ]; +int err; + +BT_DBG ("w %16phN" , w); +BT_DBG ("n1 %16phN n2 %16phN" , n1, n2); +BT_DBG ("r %16phN io_cap %3phN a1 %7phN a2 %7phN" , r, io_cap, a1, a2); + +memcpy (m, a2,7 ); +memcpy (m +7 , a1,7 ); +memcpy (m +14 , io_cap,3 ); +memcpy (m +17 , r,16 ); +memcpy (m +33 , n2,16 ); +memcpy (m +49 , n1,16 ); + + err =aes_cmac (tfm_cmac, w, m,sizeof (m), res); +if (err) +return err; + +BT_DBG ("res %16phN" , res); + +return err; +} +static int smp_g2 (struct crypto_hash *tfm_cmac,const u8 u[32 ],const u8 v[32 ],const u8 x[16 ],const u8 y[16 ],u32 *val) {
@@ -1001,6 +1082,69 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)return smp; } +static int sc_mackey_and_ltk (struct smp_chan *smp,u8 mackey[16 ],u8 ltk[16 ]) +{ +struct hci_conn *hcon = smp->conn->hcon; +u8 *na, *nb, a[7 ], b[7 ]; + +if (hcon->out) { + na = smp->prnd; + nb = smp->rrnd; + }else { + na = smp->rrnd; + nb = smp->prnd; + } + +memcpy (a, &hcon->init_addr,6 ); +memcpy (b, &hcon->resp_addr,6 ); + a[6 ] = hcon->init_addr_type; + b[6 ] = hcon->resp_addr_type; + +return smp_f5 (smp->tfm_cmac, smp->dhkey, na, nb, a, b, mackey, ltk); +} + +static int sc_user_reply (struct smp_chan *smp,u16 mgmt_op,__le32 passkey) +{ +struct hci_conn *hcon = smp->conn->hcon; +struct smp_cmd_dhkey_check check; +u8 a[7 ], b[7 ], *local_addr, *remote_addr; +u8 io_cap[3 ], r[16 ]; + +switch (mgmt_op) { +case MGMT_OP_USER_PASSKEY_NEG_REPLY : +smp_failure (smp->conn,SMP_PASSKEY_ENTRY_FAILED ); +return 0 ; +case MGMT_OP_USER_CONFIRM_NEG_REPLY : +smp_failure (smp->conn,SMP_NUMERIC_COMP_FAILED ); +return 0 ; + } + +memcpy (a, &hcon->init_addr,6 ); +memcpy (b, &hcon->resp_addr,6 ); + a[6 ] = hcon->init_addr_type; + b[6 ] = hcon->resp_addr_type; + +if (hcon->out) { + local_addr = a; + remote_addr = b; +memcpy (io_cap, &smp->preq[1 ],3 ); + }else { + local_addr = b; + remote_addr = a; +memcpy (io_cap, &smp->prsp[1 ],3 ); + } + +memcpy (r, &passkey,sizeof (passkey)); +memset (r +sizeof (passkey),0 ,sizeof (r) -sizeof (passkey)); + +smp_f6 (smp->tfm_cmac, smp->mackey, smp->prnd, smp->rrnd, r, io_cap, + local_addr, remote_addr, check.e); + +smp_send_cmd (smp->conn,SMP_CMD_DHKEY_CHECK ,sizeof (check), &check); + +return 0 ; +} +int smp_user_confirm_reply (struct hci_conn *hcon,u16 mgmt_op,__le32 passkey) {struct l2cap_conn *conn = hcon->l2cap_data;
@@ -1026,6 +1170,11 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey) smp = chan->data; +if (test_bit (SMP_FLAG_SC , &smp->flags)) { + err =sc_user_reply (smp, mgmt_op, passkey); + goto unlock; + } +switch (mgmt_op) {case MGMT_OP_USER_PASSKEY_REPLY : value =le32_to_cpu (passkey);
@@ -1338,6 +1487,11 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) nb = smp->prnd; } +/* Generate MacKey and LTK */ + err =sc_mackey_and_ltk (smp, smp->mackey, smp->tk); +if (err) +return SMP_UNSPECIFIED ; + err =smp_g2 (smp->tfm_cmac, pkax, pkbx, na, nb, &passkey);if (err)return SMP_UNSPECIFIED ;
Signature · 1 line
2.1.0
PATCH 21/49 Bluetooth: Add support for LE SC DHKey check PDU
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
Once we receive the DHKey check PDU it's time to first verify that the value is correct and then proceed with encrypting the link.
--- net/bluetooth/smp.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+)
net/bluetooth/smp.c +56 -0
@@ -1894,6 +1894,58 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)return 0 ; } +static int smp_cmd_dhkey_check (struct l2cap_conn *conn,struct sk_buff *skb) +{ +struct smp_cmd_dhkey_check *check = (void *) skb->data; +struct l2cap_chan *chan = conn->smp; +struct hci_conn *hcon = conn->hcon; +struct smp_chan *smp = chan->data; +u8 a[7 ], b[7 ], *local_addr, *remote_addr; +u8 io_cap[3 ], r[16 ], e[16 ]; +int err; + +BT_DBG ("conn %p" , conn); + +if (skb->len <sizeof (*check)) +return SMP_INVALID_PARAMS ; + +memcpy (a, &hcon->init_addr,6 ); +memcpy (b, &hcon->resp_addr,6 ); + a[6 ] = hcon->init_addr_type; + b[6 ] = hcon->resp_addr_type; + +if (hcon->out) { + local_addr = a; + remote_addr = b; +memcpy (io_cap, &smp->prsp[1 ],3 ); + }else { + local_addr = b; + remote_addr = a; +memcpy (io_cap, &smp->preq[1 ],3 ); + } + +memset (r,0 ,sizeof (r)); + + err =smp_f6 (smp->tfm_cmac, smp->mackey, smp->rrnd, smp->prnd, r, + io_cap, remote_addr, local_addr, e); +if (err) +return SMP_UNSPECIFIED ; + +if (memcmp (check->e, e,16 )) +return SMP_DHKEY_CHECK_FAILED ; + + smp->ltk =hci_add_ltk (hcon->hdev, &hcon->dst, hcon->dst_type, +SMP_LTK_P256 ,0 , smp->tk, smp->enc_key_size, +0 ,0 ); + +if (hcon->out) { +hci_le_start_enc (hcon,0 ,0 , smp->tk); + hcon->enc_key_size = smp->enc_key_size; + } + +return 0 ; +} +static int smp_sig_channel (struct l2cap_chan *chan,struct sk_buff *skb) {struct l2cap_conn *conn = chan->conn;
@@ -1982,6 +2034,10 @@ static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb) reason =smp_cmd_public_key (conn, skb);break ; +case SMP_CMD_DHKEY_CHECK : + reason =smp_cmd_dhkey_check (conn, skb); +break ; +default :BT_DBG ("Unknown command code 0x%2.2x" , code); reason =SMP_CMD_NOTSUPP ;
Signature · 1 line
2.1.0
PATCH 22/49 Bluetooth: Add support for LE SC key generation
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
As the last step of the LE SC pairing process it's time to generate and distribute keys. The generation part is unique to LE SC and so this patch adds a dedicated function for it. We also clear the distribution bits for keys which are not distributed with LE SC, so that the code shared with legacy SMP will not go ahead and try to distribute them.
--- net/bluetooth/smp.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+)
net/bluetooth/smp.c +57 -0
@@ -77,6 +77,7 @@ struct smp_chan {struct smp_ltk *ltk;struct smp_ltk *slave_ltk;struct smp_irk *remote_irk; +u8 *link_key;unsigned long flags;/* Secure Connections variables */
@@ -321,6 +322,22 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)return err; } +static int smp_h6 (struct crypto_hash *tfm_cmac,const u8 w[16 ], +const u8 key_id[4 ],u8 res[16 ]) +{ +int err; + +BT_DBG ("w %16phN key_id %4phN" , w, key_id); + + err =aes_cmac (tfm_cmac, w, key_id,4 , res); +if (err) +return err; + +BT_DBG ("res %16phN" , res); + +return err; +} +static int smp_ah (struct crypto_blkcipher *tfm,u8 irk[16 ],u8 r[3 ],u8 res[3 ]) {u8 _res[16 ];
@@ -594,6 +611,7 @@ static void smp_chan_destroy(struct l2cap_conn *conn)kfree (smp->csrk);kfree (smp->slave_csrk); +kfree (smp->link_key);crypto_free_blkcipher (smp->tfm_aes);crypto_free_hash (smp->tfm_cmac);
@@ -907,6 +925,37 @@ static void smp_notify_keys(struct l2cap_conn *conn)bacpy (&smp->slave_ltk->bdaddr, &hcon->dst);mgmt_new_ltk (hdev, smp->slave_ltk, persistent); } + +if (smp->link_key) { +hci_add_link_key (hdev, smp->conn->hcon, &hcon->dst, + smp->link_key,HCI_LK_AUTH_COMBINATION_P256 , +0 ,NULL ); + } +} + +static void sc_generate_link_key (struct smp_chan *smp) +{ +/* These constants are as specified in the core specification. +* In ASCII they spell out to 'tmp1' and 'lebr'. +*/ +const u8 tmp1[4 ] = {0x31 ,0x70 ,0x6d ,0x74 }; +const u8 lebr[4 ] = {0x72 ,0x62 ,0x65 ,0x6c }; + + smp->link_key =kzalloc (16 ,GFP_KERNEL ); +if (!smp->link_key) +return ; + +if (smp_h6 (smp->tfm_cmac, smp->tk, tmp1, smp->link_key)) { +kfree (smp->link_key); + smp->link_key =NULL ; +return ; + } + +if (smp_h6 (smp->tfm_cmac, smp->link_key, lebr, smp->link_key)) { +kfree (smp->link_key); + smp->link_key =NULL ; +return ; + } }static void smp_allow_key_dist (struct smp_chan *smp)
@@ -951,6 +1000,14 @@ static void smp_distribute_keys(struct smp_chan *smp) *keydist &= req->resp_key_dist; } +if (test_bit (SMP_FLAG_SC , &smp->flags)) { +if (*keydist &SMP_DIST_LINK_KEY ) +sc_generate_link_key (smp); + +/* Clear the keys which are generated but not distributed */ + *keydist &= ~SMP_SC_NO_DIST ; + } +BT_DBG ("keydist 0x%x" , *keydist);if (*keydist &SMP_DIST_ENC_KEY ) {
Signature · 1 line
2.1.0
PATCH 23/49 Bluetooth: Track authentication method in SMP context
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
For Secure Connections we'll select the authentication method as soon as we receive the public key, but only use it later (both when actually triggering the method as well as when determining the quality of the resulting LTK). Store the method therefore in the SMP context.
--- net/bluetooth/smp.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-)
net/bluetooth/smp.c +17 -15
@@ -79,6 +79,7 @@ struct smp_chan {struct smp_irk *remote_irk;u8 *link_key;unsigned long flags; +u8 method;/* Secure Connections variables */ u8 local_pk[64 ];
@@ -688,7 +689,6 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,struct hci_conn *hcon = conn->hcon;struct l2cap_chan *chan = conn->smp;struct smp_chan *smp = chan->data; -u8 method;u32 passkey =0 ;int ret =0 ;
@@ -705,26 +705,28 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,* table. */ if (!(auth &SMP_AUTH_MITM )) - method =JUST_CFM ; + smp->method =JUST_CFM ;else - method =get_auth_method (smp, local_io, remote_io); + smp->method =get_auth_method (smp, local_io, remote_io);/* Don't confirm locally initiated pairing attempts */ -if (method ==JUST_CFM &&test_bit (SMP_FLAG_INITIATOR , &smp->flags)) - method =JUST_WORKS ; +if (smp->method ==JUST_CFM &&test_bit (SMP_FLAG_INITIATOR , + &smp->flags)) + smp->method =JUST_WORKS ;/* Don't bother user space with no IO capabilities */ -if (method ==JUST_CFM && hcon->io_capability ==HCI_IO_NO_INPUT_OUTPUT ) - method =JUST_WORKS ; +if (smp->method ==JUST_CFM && + hcon->io_capability ==HCI_IO_NO_INPUT_OUTPUT ) + smp->method =JUST_WORKS ;/* If Just Works, Continue with Zero TK */ -if (method ==JUST_WORKS ) { +if (smp->method ==JUST_WORKS ) {set_bit (SMP_FLAG_TK_VALID , &smp->flags);return 0 ; }/* Not Just Works/Confirm results in MITM Authentication */ -if (method !=JUST_CFM ) { +if (smp->method !=JUST_CFM ) {set_bit (SMP_FLAG_MITM_AUTH , &smp->flags);if (hcon->pending_sec_level <BT_SECURITY_HIGH ) hcon->pending_sec_level =BT_SECURITY_HIGH ;
@@ -733,15 +735,15 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,/* If both devices have Keyoard-Display I/O, the master * Confirms and the slave Enters the passkey. */ -if (method ==OVERLAP ) { +if (smp->method ==OVERLAP ) {if (hcon->role ==HCI_ROLE_MASTER ) - method =CFM_PASSKEY ; + smp->method =CFM_PASSKEY ;else - method =REQ_PASSKEY ; + smp->method =REQ_PASSKEY ; }/* Generate random passkey. */ -if (method ==CFM_PASSKEY ) { +if (smp->method ==CFM_PASSKEY ) {memset (smp->tk,0 ,sizeof (smp->tk));get_random_bytes (&passkey,sizeof (passkey)); passkey %=1000000 ;
@@ -750,10 +752,10 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,set_bit (SMP_FLAG_TK_VALID , &smp->flags); } -if (method ==REQ_PASSKEY ) +if (smp->method ==REQ_PASSKEY ) ret =mgmt_user_passkey_request (hcon->hdev, &hcon->dst, hcon->type, hcon->dst_type); -else if (method ==JUST_CFM ) +else if (smp->method ==JUST_CFM ) ret =mgmt_user_confirm_request (hcon->hdev, &hcon->dst, hcon->type, hcon->dst_type, passkey,1 );
Signature · 1 line
2.1.0
PATCH 24/49 Bluetooth: Add selection of the SC authentication method
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
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.
--- net/bluetooth/smp.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 5 deletions(-)
net/bluetooth/smp.c +69 -5
@@ -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 0xFFstatic 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. */
Signature · 1 line
2.1.0
PATCH 25/49 Bluetooth: Detect SMP SC debug keys
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
We need to be able to detect if the remote side used a debug key for the pairing. This patch adds the debug key defines and sets a flag to indicate that a debug key was used. The debug private key (debug_sk) is also added in this patch but will only be used in a subsequent patch when local debug key support is implemented.
--- net/bluetooth/smp.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+)
net/bluetooth/smp.c +27 -0
@@ -54,6 +54,7 @@ enum {SMP_FLAG_INITIATOR ,SMP_FLAG_SC ,SMP_FLAG_REMOTE_PK , + SMP_FLAG_DEBUG_KEY, }; struct smp_chan {
@@ -92,6 +93,29 @@ struct smp_chan {struct crypto_hash *tfm_cmac; }; +/* These debug key values are defined in the SMP section of the core +* specification. debug_pk is the public debug key and debug_sk the +* private debug key. +*/ +static const u8 debug_pk[64 ] = { +0xe6 ,0x9d ,0x35 ,0x0e ,0x48 ,0x01 ,0x03 ,0xcc , +0xdb ,0xfd ,0xf4 ,0xac ,0x11 ,0x91 ,0xf4 ,0xef , +0xb9 ,0xa5 ,0xf9 ,0xe9 ,0xa7 ,0x83 ,0x2c ,0x5e , +0x2c ,0xbe ,0x97 ,0xf2 ,0xd2 ,0x03 ,0xb0 ,0x20 , + +0x8b ,0xd2 ,0x89 ,0x15 ,0xd0 ,0x8e ,0x1c ,0x74 , +0x24 ,0x30 ,0xed ,0x8f ,0xc2 ,0x45 ,0x63 ,0x76 , +0x5c ,0x15 ,0x52 ,0x5a ,0xbf ,0x9a ,0x32 ,0x63 , +0x6d ,0xeb ,0x2a ,0x65 ,0x49 ,0x9c ,0x80 ,0xdc , +}; + +static const u8 debug_sk[32 ] = { +0xbd ,0x1a ,0x3c ,0xcd ,0xa6 ,0xb8 ,0x99 ,0x58 , +0x99 ,0xb7 ,0x40 ,0xeb ,0x7b ,0x60 ,0xff ,0x4a , +0x50 ,0x3f ,0x10 ,0xd2 ,0xe3 ,0xb3 ,0xc9 ,0x74 , +0x38 ,0x5f ,0xc5 ,0xa3 ,0xd4 ,0xf6 ,0x49 ,0x3f , +}; +static inline void swap_buf (const u8 *src,u8 *dst,size_t len) {size_t i;
@@ -2000,6 +2024,9 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)else hcon->pending_sec_level =BT_SECURITY_FIPS ; +if (!memcmp (debug_pk, smp->remote_pk,64 )) +set_bit (SMP_FLAG_DEBUG_KEY , &smp->flags); +/* The Initiating device waits for the non-initiating device to * send the confirm value. */
Signature · 1 line
2.1.0
PATCH 26/49 Bluetooth: Add check for accidentally generating a debug key
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
It is very unlikely, but to have a 100% guarantee of the generated key type we need to reject any keys which happen to match the debug key.
--- net/bluetooth/smp.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
net/bluetooth/smp.c +11 -3
@@ -1399,9 +1399,17 @@ static u8 sc_send_public_key(struct smp_chan *smp) {BT_DBG ("" ); -/* Generate local key pair for Secure Connections */ -if (!ecc_make_key (smp->local_pk, smp->local_sk)) -return SMP_UNSPECIFIED ; +while (true) { +/* Generate local key pair for Secure Connections */ +if (!ecc_make_key (smp->local_pk, smp->local_sk)) +return SMP_UNSPECIFIED ; + +/* This is unlikely, but we need to check that we didn't +* accidentially generate a debug key. +*/ +if (memcmp (smp->local_sk, debug_sk,32 )) +break ; + }BT_DBG ("Local Public Key X: %32phN" , smp->local_pk);BT_DBG ("Local Public Key Y: %32phN" , &smp->local_pk[32 ]);
Signature · 1 line
2.1.0
PATCH 27/49 Bluetooth: Set correct LTK type and authentication for SC
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
After generating the LTK we should set the correct type (normal SC or debug) and authentication information for it.
--- net/bluetooth/smp.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
net/bluetooth/smp.c +12 -1
@@ -2060,6 +2060,7 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb)struct smp_chan *smp = chan->data;u8 a[7 ], b[7 ], *local_addr, *remote_addr;u8 io_cap[3 ], r[16 ], e[16 ]; +u8 key_type, auth;int err;BT_DBG ("conn %p" , conn);
@@ -2092,8 +2093,18 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb)if (memcmp (check->e, e,16 ))return SMP_DHKEY_CHECK_FAILED ; +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 ; + smp->ltk =hci_add_ltk (hcon->hdev, &hcon->dst, hcon->dst_type, -SMP_LTK_P256 ,0 , smp->tk, smp->enc_key_size, + key_type, auth, smp->tk, smp->enc_key_size,0 ,0 );if (hcon->out) {
Signature · 1 line
2.1.0
PATCH 28/49 Bluetooth: Add support for SC just-works pairing
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
If the just-works method was chosen we shouldn't send anything to user space but simply proceed with sending the DHKey Check PDU. This patch adds the necessary code for it.
--- net/bluetooth/smp.c | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-)
net/bluetooth/smp.c +27 -12
@@ -1198,22 +1198,13 @@ static int sc_mackey_and_ltk(struct smp_chan *smp, u8 mackey[16], u8 ltk[16])return smp_f5 (smp->tfm_cmac, smp->dhkey, na, nb, a, b, mackey, ltk); } -static int sc_user_reply (struct smp_chan *smp,u16 mgmt_op,__le32 passkey) +static void sc_dhkey_check (struct smp_chan *smp,__le32 passkey) {struct hci_conn *hcon = smp->conn->hcon;struct smp_cmd_dhkey_check check;u8 a[7 ], b[7 ], *local_addr, *remote_addr;u8 io_cap[3 ], r[16 ]; -switch (mgmt_op) { -case MGMT_OP_USER_PASSKEY_NEG_REPLY : -smp_failure (smp->conn,SMP_PASSKEY_ENTRY_FAILED ); -return 0 ; -case MGMT_OP_USER_CONFIRM_NEG_REPLY : -smp_failure (smp->conn,SMP_NUMERIC_COMP_FAILED ); -return 0 ; - } -memcpy (a, &hcon->init_addr,6 );memcpy (b, &hcon->resp_addr,6 ); a[6 ] = hcon->init_addr_type;
@@ -1229,13 +1220,29 @@ static int sc_user_reply(struct smp_chan *smp, u16 mgmt_op, __le32 passkey)memcpy (io_cap, &smp->prsp[1 ],3 ); } -memcpy (r, &passkey,sizeof (passkey)); -memset (r +sizeof (passkey),0 ,sizeof (r) -sizeof (passkey)); +memset (r,0 ,sizeof (r)); + +if (smp->method ==REQ_PASSKEY || smp->method ==DSP_PASSKEY ) +memcpy (r, &passkey,sizeof (passkey));smp_f6 (smp->tfm_cmac, smp->mackey, smp->prnd, smp->rrnd, r, io_cap, local_addr, remote_addr, check.e);smp_send_cmd (smp->conn,SMP_CMD_DHKEY_CHECK ,sizeof (check), &check); +} + +static int sc_user_reply (struct smp_chan *smp,u16 mgmt_op,__le32 passkey) +{ +switch (mgmt_op) { +case MGMT_OP_USER_PASSKEY_NEG_REPLY : +smp_failure (smp->conn,SMP_PASSKEY_ENTRY_FAILED ); +return 0 ; +case MGMT_OP_USER_CONFIRM_NEG_REPLY : +smp_failure (smp->conn,SMP_NUMERIC_COMP_FAILED ); +return 0 ; + } + +sc_dhkey_check (smp, passkey);return 0 ; }
@@ -1599,6 +1606,14 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)if (err)return SMP_UNSPECIFIED ; +if (smp->method ==JUST_WORKS ) { +if (hcon->out) { +sc_dhkey_check (smp, passkey); +SMP_ALLOW_CMD (smp,SMP_CMD_DHKEY_CHECK ); + } +return 0 ; + } + err =mgmt_user_confirm_request (hcon->hdev, &hcon->dst, hcon->type, hcon->dst_type, passkey,0 );
Signature · 1 line
2.1.0
PATCH 29/49 Bluetooth: Fix BR/EDR Link Key type when derived through LE SC
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
We need to set the correct Link Key type based on the properties of the LE SC pairing that it was derived from. If debug keys were used the type should be a debug key, and the authenticated vs unauthenticated information should be set on what kind of security level was reached.
--- net/bluetooth/hci_core.c | 4 ++++ net/bluetooth/smp.c | 27 ++++++++++++++++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-)
net/bluetooth/hci_core.c +4 -0
@@ -3160,6 +3160,10 @@ static bool hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,if (!conn)return true; +/* BR/EDR key derived using SC from an LE link */ +if (conn->type ==LE_LINK ) +return true; +/* Neither local nor remote side had no-bonding as requirement */ if (conn->auth_type >0x01 && conn->remote_auth >0x01 )return true;
net/bluetooth/smp.c +24 -3
@@ -965,9 +965,30 @@ static void smp_notify_keys(struct l2cap_conn *conn) }if (smp->link_key) { -hci_add_link_key (hdev, smp->conn->hcon, &hcon->dst, - smp->link_key,HCI_LK_AUTH_COMBINATION_P256 , -0 ,NULL ); +struct link_key *key; +u8 type; + +if (test_bit (SMP_FLAG_DEBUG_KEY , &smp->flags)) + type =HCI_LK_DEBUG_COMBINATION ; +else if (hcon->sec_level ==BT_SECURITY_FIPS ) + type =HCI_LK_AUTH_COMBINATION_P256 ; +else + type =HCI_LK_UNAUTH_COMBINATION_P256 ; + + key =hci_add_link_key (hdev, smp->conn->hcon, &hcon->dst, + smp->link_key, type,0 , &persistent); +if (key) { +mgmt_new_link_key (hdev, key, persistent); + +/* Don't keep debug keys around if the relevant +* flag is not set. +*/ +if (!test_bit (HCI_KEEP_DEBUG_KEYS , &hdev->dev_flags) && + key->type ==HCI_LK_DEBUG_COMBINATION ) { +list_del_rcu (&key->list); +kfree_rcu (key, rcu); + } + } } }
Signature · 1 line
2.1.0
PATCH 30/49 Bluetooth: Add passkey entry support for LE SC
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
The passkey entry mechanism involves either both sides requesting the user for a passkey, or one side requesting the passkey while the other one displays it. The behavior as far as SMP PDUs are concerned are considerably different from numeric comparison and therefore requires several new functions to handle it.
In essence passkey entry involves both sides gradually committing to each bit of the passkey which involves 20 rounds of pairing confirm and pairing random PDUS being sent in both directions.
This patch adds a new smp->passkey_round variable to track the current round of the passkey commitment and reuses the variables already present in struct hci_conn for the passkey and entered key count.
--- net/bluetooth/smp.c | 191 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 180 insertions(+), 11 deletions(-)
net/bluetooth/smp.c +180 -11
@@ -55,6 +55,7 @@ enum {SMP_FLAG_SC ,SMP_FLAG_REMOTE_PK ,SMP_FLAG_DEBUG_KEY , + SMP_FLAG_WAIT_USER, }; struct smp_chan {
@@ -81,6 +82,7 @@ struct smp_chan {u8 *link_key;unsigned long flags;u8 method; +u8 passkey_round;/* Secure Connections variables */ u8 local_pk[64 ];
@@ -1219,7 +1221,7 @@ static int sc_mackey_and_ltk(struct smp_chan *smp, u8 mackey[16], u8 ltk[16])return smp_f5 (smp->tfm_cmac, smp->dhkey, na, nb, a, b, mackey, ltk); } -static void sc_dhkey_check (struct smp_chan *smp,__le32 passkey) +static void sc_dhkey_check (struct smp_chan *smp) {struct hci_conn *hcon = smp->conn->hcon;struct smp_cmd_dhkey_check check;
@@ -1244,7 +1246,7 @@ static void sc_dhkey_check(struct smp_chan *smp, __le32 passkey)memset (r,0 ,sizeof (r));if (smp->method ==REQ_PASSKEY || smp->method ==DSP_PASSKEY ) -memcpy (r, &passkey,sizeof (passkey)); +put_unaligned_le32 (hcon->passkey_notify, r);smp_f6 (smp->tfm_cmac, smp->mackey, smp->prnd, smp->rrnd, r, io_cap, local_addr, remote_addr, check.e);
@@ -1252,8 +1254,124 @@ static void sc_dhkey_check(struct smp_chan *smp, __le32 passkey)smp_send_cmd (smp->conn,SMP_CMD_DHKEY_CHECK ,sizeof (check), &check); } +static u8 sc_passkey_send_confirm (struct smp_chan *smp) +{ +struct l2cap_conn *conn = smp->conn; +struct hci_conn *hcon = conn->hcon; +struct smp_cmd_pairing_confirm cfm; +u8 r; + + r = ((hcon->passkey_notify >> smp->passkey_round) &0x01 ); + r |=0x80 ; + +get_random_bytes (smp->prnd,sizeof (smp->prnd)); + +if (smp_f4 (smp->tfm_cmac, smp->local_pk, smp->remote_pk, smp->prnd, r, + cfm.confirm_val)) +return SMP_UNSPECIFIED ; + +smp_send_cmd (conn,SMP_CMD_PAIRING_CONFIRM ,sizeof (cfm), &cfm); + +return 0 ; +} + +static u8 sc_passkey_round (struct smp_chan *smp,u8 smp_op) +{ +struct l2cap_conn *conn = smp->conn; +struct hci_conn *hcon = conn->hcon; +struct hci_dev *hdev = hcon->hdev; +u8 cfm[16 ], r; + +/* Ignore the PDU if we've already done 20 rounds (0 - 19) */ +if (smp->passkey_round >=20 ) +return 0 ; + +switch (smp_op) { +case SMP_CMD_PAIRING_RANDOM : + r = ((hcon->passkey_notify >> smp->passkey_round) &0x01 ); + r |=0x80 ; + +if (smp_f4 (smp->tfm_cmac, smp->remote_pk, smp->local_pk, + smp->rrnd, r, cfm)) +return SMP_UNSPECIFIED ; + +if (memcmp (smp->pcnf, cfm,16 )) +return SMP_CONFIRM_FAILED ; + + smp->passkey_round++; + +if (smp->passkey_round ==20 ) { +/* Generate MacKey and LTK */ +if (sc_mackey_and_ltk (smp, smp->mackey, smp->tk)) +return SMP_UNSPECIFIED ; + } + +/* The round is only complete when the initiator +* receives pairing random. +*/ +if (!hcon->out) { +smp_send_cmd (conn,SMP_CMD_PAIRING_RANDOM , +sizeof (smp->prnd), smp->prnd); +if (smp->passkey_round ==20 ) { +sc_dhkey_check (smp); +SMP_ALLOW_CMD (smp,SMP_CMD_DHKEY_CHECK ); + }else { +SMP_ALLOW_CMD (smp,SMP_CMD_PAIRING_CONFIRM ); + } +return 0 ; + } + +/* Start the next round */ +if (smp->passkey_round !=20 ) +return sc_passkey_round (smp,0 ); + +/* Passkey rounds are complete - start DHKey Check */ +sc_dhkey_check (smp); +SMP_ALLOW_CMD (smp,SMP_CMD_DHKEY_CHECK ); + +break ; + +case SMP_CMD_PAIRING_CONFIRM : +if (test_bit (SMP_FLAG_WAIT_USER , &smp->flags)) { +set_bit (SMP_FLAG_CFM_PENDING , &smp->flags); +return 0 ; + } + +SMP_ALLOW_CMD (smp,SMP_CMD_PAIRING_RANDOM ); + +if (hcon->out) { +smp_send_cmd (conn,SMP_CMD_PAIRING_RANDOM , +sizeof (smp->prnd), smp->prnd); +return 0 ; + } + +return sc_passkey_send_confirm (smp); + +case SMP_CMD_PUBLIC_KEY : +default : +/* Initiating device starts the round */ +if (!hcon->out) +return 0 ; + +BT_DBG ("%s Starting passkey round %u" , hdev->name, + smp->passkey_round +1 ); + +SMP_ALLOW_CMD (smp,SMP_CMD_PAIRING_CONFIRM ); + +return sc_passkey_send_confirm (smp); + } + +return 0 ; +} +static int sc_user_reply (struct smp_chan *smp,u16 mgmt_op,__le32 passkey) { +struct l2cap_conn *conn = smp->conn; +struct hci_conn *hcon = conn->hcon; +u8 smp_op; + +clear_bit (SMP_FLAG_WAIT_USER , &smp->flags); +switch (mgmt_op) {case MGMT_OP_USER_PASSKEY_NEG_REPLY :smp_failure (smp->conn,SMP_PASSKEY_ENTRY_FAILED );
@@ -1261,9 +1379,22 @@ static int sc_user_reply(struct smp_chan *smp, u16 mgmt_op, __le32 passkey)case MGMT_OP_USER_CONFIRM_NEG_REPLY :smp_failure (smp->conn,SMP_NUMERIC_COMP_FAILED );return 0 ; +case MGMT_OP_USER_PASSKEY_REPLY : + hcon->passkey_notify =le32_to_cpu (passkey); + smp->passkey_round =0 ; + +if (test_and_clear_bit (SMP_FLAG_CFM_PENDING , &smp->flags)) + smp_op =SMP_CMD_PAIRING_CONFIRM ; +else + smp_op =0 ; + +if (sc_passkey_round (smp, smp_op)) +return -EIO ; + +return 0 ; } -sc_dhkey_check (smp, passkey); +sc_dhkey_check (smp);return 0 ; }
@@ -1532,6 +1663,9 @@ static u8 sc_check_confirm(struct smp_chan *smp)if (!test_bit (SMP_FLAG_REMOTE_PK , &smp->flags))return SMP_UNSPECIFIED ; +if (smp->method ==REQ_PASSKEY || smp->method ==DSP_PASSKEY ) +return sc_passkey_round (smp,SMP_CMD_PAIRING_CONFIRM ); +if (conn->hcon->out) {smp_send_cmd (conn,SMP_CMD_PAIRING_RANDOM ,sizeof (smp->prnd), smp->prnd);
@@ -1592,6 +1726,10 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)if (!test_bit (SMP_FLAG_SC , &smp->flags))return smp_random (smp); +/* Passkey entry has special treatment */ +if (smp->method ==REQ_PASSKEY || smp->method ==DSP_PASSKEY ) +return sc_passkey_round (smp,SMP_CMD_PAIRING_RANDOM ); +if (hcon->out) {u8 cfm[16 ];
@@ -1623,24 +1761,25 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)if (err)return SMP_UNSPECIFIED ; - err =smp_g2 (smp->tfm_cmac, pkax, pkbx, na, nb, &passkey); -if (err) -return SMP_UNSPECIFIED ; -if (smp->method ==JUST_WORKS ) {if (hcon->out) { -sc_dhkey_check (smp, passkey); +sc_dhkey_check (smp);SMP_ALLOW_CMD (smp,SMP_CMD_DHKEY_CHECK ); }return 0 ; } - err =mgmt_user_confirm_request (hcon->hdev, &hcon->dst, - hcon->type, hcon->dst_type, - passkey,0 ); + err =smp_g2 (smp->tfm_cmac, pkax, pkbx, na, nb, &passkey); +if (err) +return SMP_UNSPECIFIED ; + + err =mgmt_user_confirm_request (hcon->hdev, &hcon->dst, hcon->type, + hcon->dst_type, passkey,0 );if (err)return SMP_UNSPECIFIED ; +set_bit (SMP_FLAG_WAIT_USER , &smp->flags); +return 0 ; }
@@ -2071,6 +2210,33 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)if (!memcmp (debug_pk, smp->remote_pk,64 ))set_bit (SMP_FLAG_DEBUG_KEY , &smp->flags); +if (smp->method ==DSP_PASSKEY ) { +get_random_bytes (&hcon->passkey_notify, +sizeof (hcon->passkey_notify)); + hcon->passkey_notify %=1000000 ; + hcon->passkey_entered =0 ; + smp->passkey_round =0 ; +if (mgmt_user_passkey_notify (hdev, &hcon->dst, hcon->type, + hcon->dst_type, + hcon->passkey_notify, + hcon->passkey_entered)) +return SMP_UNSPECIFIED ; +SMP_ALLOW_CMD (smp,SMP_CMD_PAIRING_CONFIRM ); +return sc_passkey_round (smp,SMP_CMD_PUBLIC_KEY ); + } + +if (hcon->out) +SMP_ALLOW_CMD (smp,SMP_CMD_PAIRING_CONFIRM ); + +if (smp->method ==REQ_PASSKEY ) { +if (mgmt_user_passkey_request (hdev, &hcon->dst, hcon->type, + hcon->dst_type)) +return SMP_UNSPECIFIED ; +SMP_ALLOW_CMD (smp,SMP_CMD_PAIRING_CONFIRM ); +set_bit (SMP_FLAG_WAIT_USER , &smp->flags); +return 0 ; + } +/* The Initiating device waits for the non-initiating device to * send the confirm value. */
@@ -2121,6 +2287,9 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb)memset (r,0 ,sizeof (r)); +if (smp->method ==REQ_PASSKEY || smp->method ==DSP_PASSKEY ) +put_unaligned_le32 (hcon->passkey_notify, r); + err =smp_f6 (smp->tfm_cmac, smp->mackey, smp->rrnd, smp->prnd, r, io_cap, remote_addr, local_addr, e);if (err)
Signature · 1 line
2.1.0
PATCH 31/49 Bluetooth: Fix DHKey Check sending order for slave role
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
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.
--- net/bluetooth/smp.c | 60 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 17 deletions(-)
net/bluetooth/smp.c +43 -17
@@ -56,6 +56,7 @@ enum {SMP_FLAG_REMOTE_PK ,SMP_FLAG_DEBUG_KEY ,SMP_FLAG_WAIT_USER , + SMP_FLAG_DHKEY_PENDING, }; struct smp_chan {
@@ -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) {/* 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)if (!hcon->out) {smp_send_cmd (conn,SMP_CMD_PAIRING_RANDOM ,sizeof (smp->prnd), smp->prnd); -if (smp->passkey_round ==20 ) { -sc_dhkey_check (smp); +if (smp->passkey_round ==20 )SMP_ALLOW_CMD (smp,SMP_CMD_DHKEY_CHECK ); - }else { +else SMP_ALLOW_CMD (smp,SMP_CMD_PAIRING_CONFIRM ); - }return 0 ; }
@@ -1394,7 +1416,14 @@ static int sc_user_reply(struct smp_chan *smp, u16 mgmt_op, __le32 passkey)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 ; }
@@ -2262,7 +2291,6 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb)struct smp_chan *smp = chan->data;u8 a[7 ], b[7 ], *local_addr, *remote_addr;u8 io_cap[3 ], r[16 ], e[16 ]; -u8 key_type, auth;int err;BT_DBG ("conn %p" , conn);
@@ -2298,19 +2326,17 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb)if (memcmp (check->e, e,16 ))return SMP_DHKEY_CHECK_FAILED ; -if (test_bit (SMP_FLAG_DEBUG_KEY , &smp->flags)) - key_type =SMP_LTK_P256_DEBUG ; -else - key_type =SMP_LTK_P256 ; +if (!hcon->out) { +if (test_bit (SMP_FLAG_WAIT_USER , &smp->flags)) { +set_bit (SMP_FLAG_DHKEY_PENDING , &smp->flags); +return 0 ; + } -if (hcon->pending_sec_level ==BT_SECURITY_FIPS ) - auth =1 ; -else - auth =0 ; +/* Slave sends DHKey check as response to master */ +sc_dhkey_check (smp); + } - smp->ltk =hci_add_ltk (hcon->hdev, &hcon->dst, hcon->dst_type, - key_type, auth, smp->tk, smp->enc_key_size, -0 ,0 ); +sc_add_ltk (smp);if (hcon->out) {hci_le_start_enc (hcon,0 ,0 , smp->tk);
Signature · 1 line
2.1.0
PATCH 32/49 Bluetooth: Add dummy handler for LE SC keypress notification
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
Since we don not actively try to clear the keypress notification bit we might get these PDUs. To avoid failing the pairing process add a simple dummy handler for these for now.
--- net/bluetooth/smp.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
net/bluetooth/smp.c +14 -0
@@ -2346,6 +2346,16 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb)return 0 ; } +static int smp_cmd_keypress_notify (struct l2cap_conn *conn, +struct sk_buff *skb) +{ +struct smp_cmd_keypress_notify *kp = (void *) skb->data; + +BT_DBG ("value 0x%02x" , kp->value); + +return 0 ; +} +static int smp_sig_channel (struct l2cap_chan *chan,struct sk_buff *skb) {struct l2cap_conn *conn = chan->conn;
@@ -2438,6 +2448,10 @@ static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb) reason =smp_cmd_dhkey_check (conn, skb);break ; +case SMP_CMD_KEYPRESS_NOTIFY : + reason =smp_cmd_keypress_notify (conn, skb); +break ; +default :BT_DBG ("Unknown command code 0x%2.2x" , code); reason =SMP_CMD_NOTSUPP ;
Signature · 1 line
2.1.0
PATCH 33/49 Bluetooth: Use debug keys for SMP when HCI_USE_DEBUG_KEYS is set
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
The HCI_USE_DEBUG_KEYS flag is intended to force our side to always use debug keys for pairing. This means both BR/EDR SSP as well as SMP with LE Secure Connections. This patch updates the SMP code to use the debug keys instead of generating a random local key pair when the flag is set.
--- net/bluetooth/smp.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-)
net/bluetooth/smp.c +18 -9
@@ -1585,18 +1585,27 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)static u8 sc_send_public_key (struct smp_chan *smp) { +struct hci_dev *hdev = smp->conn->hcon->hdev; +BT_DBG ("" ); -while (true) { -/* Generate local key pair for Secure Connections */ -if (!ecc_make_key (smp->local_pk, smp->local_sk)) -return SMP_UNSPECIFIED ; +if (test_bit (HCI_USE_DEBUG_KEYS , &hdev->dev_flags)) { +BT_DBG ("Using debug keys" ); +memcpy (smp->local_pk, debug_pk,64 ); +memcpy (smp->local_sk, debug_sk,32 ); +set_bit (SMP_FLAG_DEBUG_KEY , &smp->flags); + }else { +while (true) { +/* Generate local key pair for Secure Connections */ +if (!ecc_make_key (smp->local_pk, smp->local_sk)) +return SMP_UNSPECIFIED ; -/* This is unlikely, but we need to check that we didn't -* accidentially generate a debug key. -*/ -if (memcmp (smp->local_sk, debug_sk,32 )) -break ; +/* This is unlikely, but we need to check that +* we didn't accidentially generate a debug key. +*/ +if (memcmp (smp->local_sk, debug_sk,32 )) +break ; + } }BT_DBG ("Local Public Key X: %32phN" , smp->local_pk);
Signature · 1 line
2.1.0
PATCH 34/49 Bluetooth: Add hci_conn flag for new link key generation
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
For LE Secure Connections we want to trigger cross transport key generation only if a new link key was actually created during the BR/EDR connection. This patch adds a new flag to track this information.
--- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_event.c | 3 +++ 2 files changed, 4 insertions(+)
include/net/bluetooth/hci_core.h +1 -0
@@ -559,6 +559,7 @@ enum {HCI_CONN_AUTH_INITIATOR ,HCI_CONN_DROP ,HCI_CONN_PARAM_REMOVAL_PEND , + HCI_CONN_NEW_LINK_KEY, };static inline bool hci_conn_ssp_enabled (struct hci_conn *conn)
net/bluetooth/hci_event.c +3 -0
@@ -3249,6 +3249,8 @@ static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb) conn =hci_conn_hash_lookup_ba (hdev,ACL_LINK , &ev->bdaddr);if (conn) { +clear_bit (HCI_CONN_NEW_LINK_KEY , &conn->flags); +if ((key->type ==HCI_LK_UNAUTH_COMBINATION_P192 || key->type ==HCI_LK_UNAUTH_COMBINATION_P256 ) && conn->auth_type !=0xff && (conn->auth_type &0x01 )) {
@@ -3301,6 +3303,7 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb) conn->disc_timeout =HCI_DISCONN_TIMEOUT ;hci_conn_drop (conn); +set_bit (HCI_CONN_NEW_LINK_KEY , &conn->flags);conn_set_key (conn, ev->key_type, conn->pin_length);if (!test_bit (HCI_MGMT , &hdev->dev_flags))
Signature · 1 line
2.1.0
PATCH 35/49 Bluetooth: Add debugfs switch for forcing SMP over BR/EDR
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
To make it possible to use LE SC functionality over BR/EDR with pre-4.1 controllers (that do not support BR/EDR SC links) it's useful to be able to force LE SC operations even over a traditional SSP protected link. This patch adds a debugfs switch to force a special debug flag which is used to skip the checks for BR/EDR SC support.
--- include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_core.c | 47 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+)
include/net/bluetooth/hci.h +1 -0
@@ -163,6 +163,7 @@ enum {enum {HCI_DUT_MODE ,HCI_FORCE_SC , +HCI_FORCE_LESC ,HCI_FORCE_STATIC_ADDR , };
net/bluetooth/hci_core.c +47 -0
59 lines not on this page · raw message
Signature · 1 line
2.1.0
PATCH 36/49 Bluetooth: Add skeleton for BR/EDR SMP channel
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
This patch adds the very basic code for creating and destroying SMP L2CAP channels for BR/EDR connections.
--- include/net/bluetooth/hci_core.h | 1 + include/net/bluetooth/l2cap.h | 2 + net/bluetooth/smp.c | 89 ++++++++++++++++++++++++++++++++-------- 3 files changed, 74 insertions(+), 18 deletions(-)
include/net/bluetooth/hci_core.h +1 -0
@@ -306,6 +306,7 @@ struct hci_dev {__u32 req_result;void *smp_data; +void *smp_bredr_data;struct discovery_state discovery;struct hci_conn_hash conn_hash;
include/net/bluetooth/l2cap.h +2 -0
@@ -141,6 +141,7 @@ struct l2cap_conninfo {#define L2CAP_FC_ATT 0x10#define L2CAP_FC_SIG_LE 0x20#define L2CAP_FC_SMP_LE 0x40 +#define L2CAP_FC_SMP_BREDR 0x80/* L2CAP Control Field bit masks */ #define L2CAP_CTRL_SAR 0xC000
@@ -255,6 +256,7 @@ struct l2cap_conn_rsp {#define L2CAP_CID_ATT 0x0004#define L2CAP_CID_LE_SIGNALING 0x0005#define L2CAP_CID_SMP 0x0006 +#define L2CAP_CID_SMP_BREDR 0x0007#define L2CAP_CID_DYN_START 0x0040#define L2CAP_CID_DYN_END 0xffff#define L2CAP_CID_LE_DYN_END 0x007f
net/bluetooth/smp.c +71 -18
147 lines not on this page · raw message
Signature · 1 line
2.1.0
PATCH 37/49 Bluetooth: Add full SMP BR/EDR support
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
When doing SMP over BR/EDR some of the routines can be shared with the LE functionality whereas others needs to be split into their own BR/EDR specific branches. This patch implements the split of BR/EDR specific SMP code from the LE-only code, making sure SMP over BR/EDR works as specified.
--- net/bluetooth/l2cap_core.c | 4 + net/bluetooth/smp.c | 230 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 212 insertions(+), 22 deletions(-)
net/bluetooth/l2cap_core.c +4 -0
@@ -6967,6 +6967,10 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) test_bit(HCI_HS_ENABLED, &hcon->hdev->dev_flags)) conn->local_fixed_chan |= L2CAP_FC_A2MP; +if (bredr_sc_enabled (hcon->hdev) && +test_bit (HCI_LE_ENABLED , &hcon->hdev->dev_flags)) + conn->local_fixed_chan |=L2CAP_FC_SMP_BREDR ; +mutex_init (&conn->ident_lock);mutex_init (&conn->chan_lock);
net/bluetooth/smp.c +208 -22
318 lines not on this page · raw message
Signature · 1 line
2.1.0
PATCH 38/49 Bluetooth: Add SC-only mode support for SMP
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
When Secure Connections-only mode is enabled we should reject any pairing command that does not have Secure Connections set in the authentication requirements. This patch adds the appropriate logic for this to the command handlers of Pairing Request/Response and Security Request.
--- net/bluetooth/smp.c | 9 +++++++++ 1 file changed, 9 insertions(+)
net/bluetooth/smp.c +9 -0
@@ -1608,6 +1608,9 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) (auth & SMP_AUTH_BONDING))return SMP_PAIRING_NOTSUPP ; +if (test_bit (HCI_SC_ONLY , &hdev->dev_flags) && !(auth &SMP_AUTH_SC )) +return SMP_AUTH_REQUIREMENTS ; + smp->preq[0 ] =SMP_CMD_PAIRING_REQ ;memcpy (&smp->preq[1 ], req,sizeof (*req));skb_pull (skb,sizeof (*req));
@@ -1752,6 +1755,9 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) auth = rsp->auth_req &AUTH_REQ_MASK (hdev); +if (test_bit (HCI_SC_ONLY , &hdev->dev_flags) && !(auth &SMP_AUTH_SC )) +return SMP_AUTH_REQUIREMENTS ; + smp->prsp[0 ] =SMP_CMD_PAIRING_RSP ;memcpy (&smp->prsp[1 ], rsp,sizeof (*rsp));
@@ -2008,6 +2014,9 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) auth = rp->auth_req &AUTH_REQ_MASK (hdev); +if (test_bit (HCI_SC_ONLY , &hdev->dev_flags) && !(auth &SMP_AUTH_SC )) +return SMP_AUTH_REQUIREMENTS ; +if (hcon->io_capability ==HCI_IO_NO_INPUT_OUTPUT ) sec_level =BT_SECURITY_MEDIUM ;else
Signature · 1 line
2.1.0
PATCH 39/49 Bluetooth: Unify remote OOB data functions
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
There's no need to duplicate code for the 192 vs 192+256 variants of the OOB data functions. This is also helpful to pave the way to support LE SC OOB data where only 256 bit data is provided.
--- include/net/bluetooth/hci_core.h | 6 ++---- net/bluetooth/hci_core.c | 46 +++++++++++++--------------------------- net/bluetooth/mgmt.c | 9 ++++---- 3 files changed, 22 insertions(+), 39 deletions(-)
include/net/bluetooth/hci_core.h +2 -4
@@ -944,10 +944,8 @@ void hci_remote_oob_data_clear(struct hci_dev *hdev);struct oob_data *hci_find_remote_oob_data (struct hci_dev *hdev,bdaddr_t *bdaddr);int hci_add_remote_oob_data (struct hci_dev *hdev,bdaddr_t *bdaddr, -u8 *hash,u8 *rand); -int hci_add_remote_oob_ext_data (struct hci_dev *hdev,bdaddr_t *bdaddr, -u8 *hash192,u8 *rand192, -u8 *hash256,u8 *rand256); +u8 *hash192,u8 *rand192, +u8 *hash256,u8 *rand256);int hci_remove_remote_oob_data (struct hci_dev *hdev,bdaddr_t *bdaddr);void hci_event_packet (struct hci_dev *hdev,struct sk_buff *skb);
net/bluetooth/hci_core.c +15 -31
60 lines not on this page · raw message
net/bluetooth/mgmt.c +5 -4
@@ -3599,7 +3599,8 @@ static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev, } err =hci_add_remote_oob_data (hdev, &cp->addr.bdaddr, - cp->hash, cp->rand); + cp->hash, cp->rand, +NULL ,NULL );if (err <0 ) status =MGMT_STATUS_FAILED ;else
@@ -3619,9 +3620,9 @@ static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev, goto unlock; } - err =hci_add_remote_oob_ext_data (hdev, &cp->addr.bdaddr, - cp->hash192, cp->rand192, - cp->hash256, cp->rand256); + err =hci_add_remote_oob_data (hdev, &cp->addr.bdaddr, + cp->hash192, cp->rand192, + cp->hash256, cp->rand256);if (err <0 ) status =MGMT_STATUS_FAILED ;else
Signature · 1 line
2.1.0
PATCH 40/49 Bluetooth: Store address type with OOB data
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
To be able to support OOB data for LE pairing we need to store the address type of the remote device. This patch extends the relevant functions and data types with a bdaddr_type variable.
--- include/net/bluetooth/hci_core.h | 8 +++++--- net/bluetooth/hci_core.c | 26 ++++++++++++++++---------- net/bluetooth/hci_event.c | 4 ++-- net/bluetooth/mgmt.c | 11 ++++++----- 4 files changed, 29 insertions(+), 20 deletions(-)
include/net/bluetooth/hci_core.h +5 -3
@@ -140,6 +140,7 @@ struct link_key {struct oob_data {struct list_head list;bdaddr_t bdaddr; +u8 bdaddr_type;u8 hash192[16 ];u8 rand192[16 ];u8 hash256[16 ];
@@ -942,11 +943,12 @@ void hci_smp_irks_clear(struct hci_dev *hdev);void hci_remote_oob_data_clear (struct hci_dev *hdev);struct oob_data *hci_find_remote_oob_data (struct hci_dev *hdev, -bdaddr_t *bdaddr); +bdaddr_t *bdaddr,u8 bdaddr_type);int hci_add_remote_oob_data (struct hci_dev *hdev,bdaddr_t *bdaddr, -u8 *hash192,u8 *rand192, +u8 bdaddr_type,u8 *hash192,u8 *rand192,u8 *hash256,u8 *rand256); -int hci_remove_remote_oob_data (struct hci_dev *hdev,bdaddr_t *bdaddr); +int hci_remove_remote_oob_data (struct hci_dev *hdev,bdaddr_t *bdaddr, +u8 bdaddr_type);void hci_event_packet (struct hci_dev *hdev,struct sk_buff *skb);
net/bluetooth/hci_core.c +16 -10
@@ -2160,7 +2160,7 @@ u32 hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,BT_DBG ("cache %p, %pMR" , cache, &data->bdaddr); -hci_remove_remote_oob_data (hdev, &data->bdaddr); +hci_remove_remote_oob_data (hdev, &data->bdaddr,BDADDR_BREDR );if (!data->ssp_mode) flags |=MGMT_DEV_FOUND_LEGACY_PAIRING ;
@@ -3479,26 +3479,31 @@ static void hci_cmd_timeout(struct work_struct *work) }struct oob_data *hci_find_remote_oob_data (struct hci_dev *hdev, -bdaddr_t *bdaddr) +bdaddr_t *bdaddr,u8 bdaddr_type) {struct oob_data *data; -list_for_each_entry (data, &hdev->remote_oob_data, list) -if (bacmp (bdaddr, &data->bdaddr) ==0 ) -return data; +list_for_each_entry (data, &hdev->remote_oob_data, list) { +if (bacmp (bdaddr, &data->bdaddr) !=0 ) +continue ; +if (data->bdaddr_type != bdaddr_type) +continue ; +return data; + }return NULL ; } -int hci_remove_remote_oob_data (struct hci_dev *hdev,bdaddr_t *bdaddr) +int hci_remove_remote_oob_data (struct hci_dev *hdev,bdaddr_t *bdaddr, +u8 bdaddr_type) {struct oob_data *data; - data =hci_find_remote_oob_data (hdev, bdaddr); + data =hci_find_remote_oob_data (hdev, bdaddr, bdaddr_type);if (!data)return -ENOENT ; -BT_DBG ("%s removing %pMR" , hdev->name, bdaddr); +BT_DBG ("%s removing %pMR (%u)" , hdev->name, bdaddr, bdaddr_type);list_del (&data->list);kfree (data);
@@ -3517,18 +3522,19 @@ void hci_remote_oob_data_clear(struct hci_dev *hdev) }int hci_add_remote_oob_data (struct hci_dev *hdev,bdaddr_t *bdaddr, -u8 *hash192,u8 *rand192, +u8 bdaddr_type,u8 *hash192,u8 *rand192,u8 *hash256,u8 *rand256) {struct oob_data *data; - data =hci_find_remote_oob_data (hdev, bdaddr); + data =hci_find_remote_oob_data (hdev, bdaddr, bdaddr_type);if (!data) { data =kmalloc (sizeof (*data),GFP_KERNEL );if (!data)return -ENOMEM ;bacpy (&data->bdaddr, bdaddr); + data->bdaddr_type = bdaddr_type;list_add (&data->list, &hdev->remote_oob_data); }
net/bluetooth/hci_event.c +2 -2
@@ -3773,7 +3773,7 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb) cp.authentication = conn->auth_type; -if (hci_find_remote_oob_data (hdev, &conn->dst) && +if (hci_find_remote_oob_data (hdev, &conn->dst,BDADDR_BREDR ) && (conn->out ||test_bit (HCI_CONN_REMOTE_OOB , &conn->flags))) cp.oob_data =0x01 ;else
@@ -4028,7 +4028,7 @@ static void hci_remote_oob_data_request_evt(struct hci_dev *hdev,if (!test_bit (HCI_MGMT , &hdev->dev_flags)) goto unlock; - data =hci_find_remote_oob_data (hdev, &ev->bdaddr); + data =hci_find_remote_oob_data (hdev, &ev->bdaddr,BDADDR_BREDR );if (data) {if (bredr_sc_enabled (hdev)) {struct hci_cp_remote_oob_ext_data_reply cp;
net/bluetooth/mgmt.c +6 -5
@@ -3599,8 +3599,8 @@ static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev, } err =hci_add_remote_oob_data (hdev, &cp->addr.bdaddr, - cp->hash, cp->rand, -NULL ,NULL ); + cp->addr.type, cp->hash, + cp->rand,NULL ,NULL );if (err <0 ) status =MGMT_STATUS_FAILED ;else
@@ -3621,8 +3621,9 @@ static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev, } err =hci_add_remote_oob_data (hdev, &cp->addr.bdaddr, - cp->hash192, cp->rand192, - cp->hash256, cp->rand256); + cp->addr.type, cp->hash192, + cp->rand192, cp->hash256, + cp->rand256);if (err <0 ) status =MGMT_STATUS_FAILED ;else
@@ -3663,7 +3664,7 @@ static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev, goto done; } - err =hci_remove_remote_oob_data (hdev, &cp->addr.bdaddr); + err =hci_remove_remote_oob_data (hdev, &cp->addr.bdaddr, cp->addr.type);if (err <0 ) status =MGMT_STATUS_INVALID_PARAMS ;else
Signature · 1 line
2.1.0
PATCH 41/49 Bluetooth: Add support for adding remote OOB data for LE
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
This patch adds proper support for passing LE OOB data to the hci_add_remote_oob_data() function. For LE the 192-bit values are not valid and should therefore be passed as NULL values.
--- net/bluetooth/mgmt.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
net/bluetooth/mgmt.c +11 -3
@@ -3610,6 +3610,7 @@ static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev, status, &cp->addr, sizeof(cp->addr)); }else if (len ==MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE ) {struct mgmt_cp_add_remote_oob_ext_data *cp = data; +u8 *rand192, *hash192;u8 status;if (cp->addr.type !=BDADDR_BREDR ) {
@@ -3620,10 +3621,17 @@ static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev, goto unlock; } +if (bdaddr_type_is_le (cp->addr.type)) { + rand192 =NULL ; + hash192 =NULL ; + }else { + rand192 = cp->rand192; + hash192 = cp->hash192; + } + err =hci_add_remote_oob_data (hdev, &cp->addr.bdaddr, - cp->addr.type, cp->hash192, - cp->rand192, cp->hash256, - cp->rand256); + cp->addr.type, hash192, rand192, + cp->hash256, cp->rand256);if (err <0 ) status =MGMT_STATUS_FAILED ;else
Signature · 1 line
2.1.0
PATCH 42/49 Bluetooth: Set SMP OOB flag if OOB data is available
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
If we have OOB data available for the remote device in question we should set the OOB flag appropriately in the SMP pairing request or response.
--- net/bluetooth/smp.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-)
net/bluetooth/smp.c +25 -6
@@ -57,6 +57,7 @@ enum {SMP_FLAG_DEBUG_KEY ,SMP_FLAG_WAIT_USER ,SMP_FLAG_DHKEY_PENDING , + SMP_FLAG_OOB, }; struct smp_chan {
@@ -562,7 +563,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,struct smp_chan *smp = chan->data;struct hci_conn *hcon = conn->hcon;struct hci_dev *hdev = hcon->hdev; -u8 local_dist =0 , remote_dist =0 ; +u8 local_dist =0 , remote_dist =0 , oob_flag =SMP_OOB_NOT_PRESENT ;if (test_bit (HCI_BONDABLE , &conn->hcon->hdev->dev_flags)) { local_dist =SMP_DIST_ENC_KEY |SMP_DIST_SIGN ;
@@ -578,19 +579,37 @@ static void build_pairing_cmd(struct l2cap_conn *conn,if (test_bit (HCI_PRIVACY , &hdev->dev_flags)) local_dist |=SMP_DIST_ID_KEY ; -if (test_bit (HCI_SC_ENABLED , &hdev->dev_flags)) { -if ((authreq &SMP_AUTH_SC ) && -test_bit (HCI_SSP_ENABLED , &hdev->dev_flags)) { +if (test_bit (HCI_SC_ENABLED , &hdev->dev_flags) && + (authreq &SMP_AUTH_SC )) { +struct oob_data *oob_data; +u8 bdaddr_type; + +if (test_bit (HCI_SSP_ENABLED , &hdev->dev_flags)) { local_dist |=SMP_DIST_LINK_KEY ; remote_dist |=SMP_DIST_LINK_KEY ; } + +if (hcon->dst_type ==ADDR_LE_DEV_PUBLIC ) + bdaddr_type =BDADDR_LE_PUBLIC ; +else + bdaddr_type =BDADDR_LE_RANDOM ; + + oob_data =hci_find_remote_oob_data (hdev, &hcon->dst, + bdaddr_type); +if (oob_data) { +set_bit (SMP_FLAG_OOB , &smp->flags); + oob_flag =SMP_OOB_PRESENT ; +memcpy (smp->rrnd, oob_data->rand256,16 ); +memcpy (smp->pcnf, oob_data->hash256,16 ); + } + }else { authreq &= ~SMP_AUTH_SC ; }if (rsp ==NULL ) { req->io_capability = conn->hcon->io_capability; - req->oob_flag =SMP_OOB_NOT_PRESENT ; + req->oob_flag = oob_flag; req->max_key_size =SMP_MAX_ENC_KEY_SIZE ; req->init_key_dist = local_dist; req->resp_key_dist = remote_dist;
@@ -601,7 +620,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, } rsp->io_capability = conn->hcon->io_capability; - rsp->oob_flag =SMP_OOB_NOT_PRESENT ; + rsp->oob_flag = oob_flag; rsp->max_key_size =SMP_MAX_ENC_KEY_SIZE ; rsp->init_key_dist = req->init_key_dist & remote_dist; rsp->resp_key_dist = req->resp_key_dist & local_dist;
Signature · 1 line
2.1.0
PATCH 43/49 Bluetooth: Add basic LE SC OOB support for remote OOB data
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
This patch adds basic OOB pairing support when we've received the remote OOB data. This includes tracking the remote r value (in smp->rr) as well as doing the appropriate f4() call when needed. Previously the OOB rand would have been stored in smp->rrnd however these are actually two independent values so we need separate variables for them. Na/Nb in the spec maps to smp->prnd/rrnd and ra/rb maps to smp->rr with smp->pr to come once local OOB data is supported.
--- net/bluetooth/smp.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-)
net/bluetooth/smp.c +36 -2
@@ -71,6 +71,7 @@ struct smp_chan {u8 rrnd[16 ];/* SMP Pairing Random (remote) */ u8 pcnf[16 ];/* SMP Pairing Confirm */ u8 tk[16 ];/* SMP Temporary Key */ +u8 rr[16 ];u8 enc_key_size;u8 remote_key_dist;bdaddr_t id_addr;
@@ -599,7 +600,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,if (oob_data) {set_bit (SMP_FLAG_OOB , &smp->flags); oob_flag =SMP_OOB_PRESENT ; -memcpy (smp->rrnd, oob_data->rand256,16 ); +memcpy (smp->rr, oob_data->rand256,16 );memcpy (smp->pcnf, oob_data->hash256,16 ); }
@@ -1334,6 +1335,9 @@ static void sc_dhkey_check(struct smp_chan *smp)if (smp->method ==REQ_PASSKEY || smp->method ==DSP_PASSKEY )put_unaligned_le32 (hcon->passkey_notify, r); +if (smp->method ==REQ_OOB ) +memcpy (r, smp->rr,16 ); +smp_f6 (smp->tfm_cmac, smp->mackey, smp->prnd, smp->rrnd, r, io_cap, local_addr, remote_addr, check.e);
@@ -1910,6 +1914,14 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)if (!test_bit (SMP_FLAG_SC , &smp->flags))return smp_random (smp); +if (smp->method ==REQ_OOB ) { +if (!hcon->out) +smp_send_cmd (conn,SMP_CMD_PAIRING_RANDOM , +sizeof (smp->prnd), smp->prnd); +SMP_ALLOW_CMD (smp,SMP_CMD_DHKEY_CHECK ); + goto mackey_and_ltk; + } +/* Passkey entry has special treatment */ if (smp->method ==REQ_PASSKEY || smp->method ==DSP_PASSKEY )return sc_passkey_round (smp,SMP_CMD_PAIRING_RANDOM );
@@ -1940,12 +1952,13 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) nb = smp->prnd; } +mackey_and_ltk:/* Generate MacKey and LTK */ err =sc_mackey_and_ltk (smp, smp->mackey, smp->tk);if (err)return SMP_UNSPECIFIED ; -if (smp->method ==JUST_WORKS ) { +if (smp->method ==JUST_WORKS || smp->method ==REQ_OOB ) {if (hcon->out) {sc_dhkey_check (smp);SMP_ALLOW_CMD (smp,SMP_CMD_DHKEY_CHECK );
@@ -2314,6 +2327,9 @@ static u8 sc_select_method(struct smp_chan *smp)struct smp_cmd_pairing *local, *remote;u8 local_mitm, remote_mitm, local_io, remote_io, method; +if (test_bit (SMP_FLAG_OOB , &smp->flags)) +return REQ_OOB ; +/* 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
@@ -2412,6 +2428,24 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)return sc_passkey_round (smp,SMP_CMD_PUBLIC_KEY ); } +if (smp->method ==REQ_OOB ) { + err =smp_f4 (smp->tfm_cmac, smp->remote_pk, smp->remote_pk, + smp->rr,0 , cfm.confirm_val); +if (err) +return SMP_UNSPECIFIED ; + +if (memcmp (cfm.confirm_val, smp->pcnf,16 )) +return SMP_CONFIRM_FAILED ; + +if (hcon->out) +smp_send_cmd (conn,SMP_CMD_PAIRING_RANDOM , +sizeof (smp->prnd), smp->prnd); + +SMP_ALLOW_CMD (smp,SMP_CMD_PAIRING_RANDOM ); + +return 0 ; + } +if (hcon->out)SMP_ALLOW_CMD (smp,SMP_CMD_PAIRING_CONFIRM );
Signature · 1 line
2.1.0
PATCH 44/49 Bluetooth: Introduce SMP_DBG macro for low-level debuging
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
The various inputs & outputs of the crypto functions as well as the values of the ECDH keys can be considered security sensitive. They should therefore not end up in dmesg by mistake. This patch introduces a new SMP_DBG macro which requires explicit compilation with -DDEBUG to be enabled. All crypto related data logs now use this macro instead of BT_DBG.
--- net/bluetooth/smp.c | 68 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 28 deletions(-)
net/bluetooth/smp.c +40 -28
@@ -32,6 +32,18 @@#include "ecc.h" #include "smp.h" +/* Low-level debug macros to be used for stuff that we don't want +* accidentially in dmesg, i.e. the values of the various crypto keys +* and the inputs & outputs of crypto functions. +*/ +#ifdef DEBUG +#define SMP_DBG (fmt, ...) printk(KERN_DEBUG "%s: " fmt, __func__, \ + ##__VA_ARGS__) +#else +#define SMP_DBG (fmt, ...) no_printk(KERN_DEBUG "%s: " fmt, __func__, \ + ##__VA_ARGS__) +#endif +#define SMP_ALLOW_CMD (smp, code) set_bit(code, &smp->allow_cmd)/* Keys which are not distributed with Secure Connections */
@@ -154,8 +166,8 @@ static int aes_cmac(struct crypto_hash *tfm, const u8 k[16], const u8 *m,swap_buf (k, tmp,16 );swap_buf (m, msg_msb, len); -BT_DBG ("msg (len %zu) %*phN" , len, len, m); -BT_DBG ("key %16phN" , k); +SMP_DBG ("msg (len %zu) %*phN" , len, len, m); +SMP_DBG ("key %16phN" , k); err =crypto_hash_setkey (tfm, tmp,16 );if (err) {
@@ -179,7 +191,7 @@ static int aes_cmac(struct crypto_hash *tfm, const u8 k[16], const u8 *m,swap_buf (mac_msb, mac,16 ); -BT_DBG ("mac %16phN" , mac); +SMP_DBG ("mac %16phN" , mac);return 0 ; }
@@ -190,9 +202,9 @@ static int smp_f4(struct crypto_hash *tfm_cmac, const u8 u[32], const u8 v[32],u8 m[65 ];int err; -BT_DBG ("u %32phN" , u); -BT_DBG ("v %32phN" , v); -BT_DBG ("x %16phN z %02x" , x, z); +SMP_DBG ("u %32phN" , u); +SMP_DBG ("v %32phN" , v); +SMP_DBG ("x %16phN z %02x" , x, z); m[0 ] = z;memcpy (m +1 , v,32 );
@@ -202,7 +214,7 @@ static int smp_f4(struct crypto_hash *tfm_cmac, const u8 u[32], const u8 v[32],if (err)return err; -BT_DBG ("res %16phN" , res); +SMP_DBG ("res %16phN" , res);return err; }
@@ -223,15 +235,15 @@ static int smp_f5(struct crypto_hash *tfm_cmac, u8 w[32], u8 n1[16], u8 n2[16],u8 m[53 ], t[16 ];int err; -BT_DBG ("w %32phN" , w); -BT_DBG ("n1 %16phN n2 %16phN" , n1, n2); -BT_DBG ("a1 %7phN a2 %7phN" , a1, a2); +SMP_DBG ("w %32phN" , w); +SMP_DBG ("n1 %16phN n2 %16phN" , n1, n2); +SMP_DBG ("a1 %7phN a2 %7phN" , a1, a2); err =aes_cmac (tfm_cmac, salt, w,32 , t);if (err)return err; -BT_DBG ("t %16phN" , t); +SMP_DBG ("t %16phN" , t);memcpy (m, length,2 );memcpy (m +2 , a2,7 );
@@ -246,7 +258,7 @@ static int smp_f5(struct crypto_hash *tfm_cmac, u8 w[32], u8 n1[16], u8 n2[16],if (err)return err; -BT_DBG ("mackey %16phN" , mackey); +SMP_DBG ("mackey %16phN" , mackey); m[52 ] =1 ;/* Counter */
@@ -254,7 +266,7 @@ static int smp_f5(struct crypto_hash *tfm_cmac, u8 w[32], u8 n1[16], u8 n2[16],if (err)return err; -BT_DBG ("ltk %16phN" , ltk); +SMP_DBG ("ltk %16phN" , ltk);return 0 ; }
@@ -267,9 +279,9 @@ static int smp_f6(struct crypto_hash *tfm_cmac, const u8 w[16],u8 m[65 ];int err; -BT_DBG ("w %16phN" , w); -BT_DBG ("n1 %16phN n2 %16phN" , n1, n2); -BT_DBG ("r %16phN io_cap %3phN a1 %7phN a2 %7phN" , r, io_cap, a1, a2); +SMP_DBG ("w %16phN" , w); +SMP_DBG ("n1 %16phN n2 %16phN" , n1, n2); +SMP_DBG ("r %16phN io_cap %3phN a1 %7phN a2 %7phN" , r, io_cap, a1, a2);memcpy (m, a2,7 );memcpy (m +7 , a1,7 );
@@ -293,9 +305,9 @@ static int smp_g2(struct crypto_hash *tfm_cmac, const u8 u[32], const u8 v[32],u8 m[80 ], tmp[16 ];int err; -BT_DBG ("u %32phN" , u); -BT_DBG ("v %32phN" , v); -BT_DBG ("x %16phN y %16phN" , x, y); +SMP_DBG ("u %32phN" , u); +SMP_DBG ("v %32phN" , v); +SMP_DBG ("x %16phN y %16phN" , x, y);memcpy (m, y,16 );memcpy (m +16 , v,32 );
@@ -308,7 +320,7 @@ static int smp_g2(struct crypto_hash *tfm_cmac, const u8 u[32], const u8 v[32], *val =get_unaligned_le32 (tmp); *val %=1000000 ; -BT_DBG ("val %06u" , *val); +SMP_DBG ("val %06u" , *val);return 0 ; }
@@ -357,13 +369,13 @@ static int smp_h6(struct crypto_hash *tfm_cmac, const u8 w[16], {int err; -BT_DBG ("w %16phN key_id %4phN" , w, key_id); +SMP_DBG ("w %16phN key_id %4phN" , w, key_id); err =aes_cmac (tfm_cmac, w, key_id,4 , res);if (err)return err; -BT_DBG ("res %16phN" , res); +SMP_DBG ("res %16phN" , res);return err; }
@@ -1742,9 +1754,9 @@ static u8 sc_send_public_key(struct smp_chan *smp) } } -BT_DBG ("Local Public Key X: %32phN" , smp->local_pk); -BT_DBG ("Local Public Key Y: %32phN" , &smp->local_pk[32 ]); -BT_DBG ("Local Private Key: %32phN" , smp->local_sk); +SMP_DBG ("Local Public Key X: %32phN" , smp->local_pk); +SMP_DBG ("Local Public Key Y: %32phN" , &smp->local_pk[32 ]); +SMP_DBG ("Local Private Key: %32phN" , smp->local_sk);smp_send_cmd (smp->conn,SMP_CMD_PUBLIC_KEY ,64 , smp->local_pk);
@@ -2390,13 +2402,13 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)return err; } -BT_DBG ("Remote Public Key X: %32phN" , smp->remote_pk); -BT_DBG ("Remote Public Key Y: %32phN" , &smp->remote_pk[32 ]); +SMP_DBG ("Remote Public Key X: %32phN" , smp->remote_pk); +SMP_DBG ("Remote Public Key Y: %32phN" , &smp->remote_pk[32 ]);if (!ecdh_shared_secret (smp->remote_pk, smp->local_sk, smp->dhkey))return SMP_UNSPECIFIED ; -BT_DBG ("DHKey %32phN" , smp->dhkey); +SMP_DBG ("DHKey %32phN" , smp->dhkey);set_bit (SMP_FLAG_REMOTE_PK , &smp->flags);
Signature · 1 line
2.1.0
PATCH 45/49 Bluetooth: Fix missing const declarations in SMP functions
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
Several SMP functions take read-only data. This patch fixes the declaration of these parameters to use the const specifier as appropriate.
--- net/bluetooth/smp.c | 18 ++++++++++-------- net/bluetooth/smp.h | 5 +++-- 2 files changed, 13 insertions(+), 10 deletions(-)
net/bluetooth/smp.c +10 -8
@@ -380,7 +380,8 @@ static int smp_h6(struct crypto_hash *tfm_cmac, const u8 w[16],return err; } -static int smp_ah (struct crypto_blkcipher *tfm,u8 irk[16 ],u8 r[3 ],u8 res[3 ]) +static int smp_ah (struct crypto_blkcipher *tfm,const u8 irk[16 ], +const u8 r[3 ],u8 res[3 ]) {u8 _res[16 ];int err;
@@ -406,7 +407,8 @@ static int smp_ah(struct crypto_blkcipher *tfm, u8 irk[16], u8 r[3], u8 res[3])return 0 ; } -bool smp_irk_matches (struct hci_dev *hdev,u8 irk[16 ],bdaddr_t *bdaddr) +bool smp_irk_matches (struct hci_dev *hdev,const u8 irk[16 ], +const bdaddr_t *bdaddr) {struct l2cap_chan *chan = hdev->smp_data;struct crypto_blkcipher *tfm;
@@ -427,7 +429,7 @@ bool smp_irk_matches(struct hci_dev *hdev, u8 irk[16], bdaddr_t *bdaddr)return !memcmp (bdaddr->b, hash,3 ); } -int smp_generate_rpa (struct hci_dev *hdev,u8 irk[16 ],bdaddr_t *rpa) +int smp_generate_rpa (struct hci_dev *hdev,const u8 irk[16 ],bdaddr_t *rpa) {struct l2cap_chan *chan = hdev->smp_data;struct crypto_blkcipher *tfm;
@@ -452,9 +454,9 @@ int smp_generate_rpa(struct hci_dev *hdev, u8 irk[16], bdaddr_t *rpa)return 0 ; } -static int smp_c1 (struct crypto_blkcipher *tfm_aes,u8 k[16 ],u8 r[16 ], -u8 preq[7 ],u8 pres[7 ],u8 _iat,bdaddr_t *ia,u8 _rat, -bdaddr_t *ra,u8 res[16 ]) +static int smp_c1 (struct crypto_blkcipher *tfm_aes,const u8 k[16 ], +const u8 r[16 ],const u8 preq[7 ],const u8 pres[7 ],u8 _iat, +const bdaddr_t *ia,u8 _rat,const bdaddr_t *ra,u8 res[16 ]) {u8 p1[16 ], p2[16 ];int err;
@@ -493,8 +495,8 @@ static int smp_c1(struct crypto_blkcipher *tfm_aes, u8 k[16], u8 r[16],return err; } -static int smp_s1 (struct crypto_blkcipher *tfm_aes,u8 k[16 ],u8 r1[16 ], -u8 r2[16 ],u8 _r[16 ]) +static int smp_s1 (struct crypto_blkcipher *tfm_aes,const u8 k[16 ], +const u8 r1[16 ],const u8 r2[16 ],u8 _r[16 ]) {int err;
net/bluetooth/smp.h +3 -2
@@ -185,8 +185,9 @@ bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level,int smp_conn_security (struct hci_conn *hcon,__u8 sec_level);int smp_user_confirm_reply (struct hci_conn *conn,u16 mgmt_op,__le32 passkey); -bool smp_irk_matches (struct hci_dev *hdev,u8 irk[16 ],bdaddr_t *bdaddr); -int smp_generate_rpa (struct hci_dev *hdev,u8 irk[16 ],bdaddr_t *rpa); +bool smp_irk_matches (struct hci_dev *hdev,const u8 irk[16 ], +const bdaddr_t *bdaddr); +int smp_generate_rpa (struct hci_dev *hdev,const u8 irk[16 ],bdaddr_t *rpa);int smp_register (struct hci_dev *hdev);void smp_unregister (struct hci_dev *hdev);
Signature · 1 line
2.1.0
PATCH 46/49 Bluetooth: Organize SMP crypto functions to logical sections
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
This patch organizes the various SMP crypto functions so that the LE SC functions appear in one section and the legacy SMP functions in a separate one.
--- net/bluetooth/smp.c | 134 ++++++++++++++++++++++++++++------------------------ 1 file changed, 71 insertions(+), 63 deletions(-)
net/bluetooth/smp.c +71 -63
@@ -141,6 +141,10 @@ static inline void swap_buf(const u8 *src, u8 *dst, size_t len) dst[len -1 - i] = src[i]; } +/* The following functions map to the LE SC SMP crypto functions +* AES-CMAC, f4, f5, f6, g2 and h6. +*/ +static int aes_cmac (struct crypto_hash *tfm,const u8 k[16 ],const u8 *m,size_t len,u8 mac[16 ]) {
@@ -325,6 +329,26 @@ static int smp_g2(struct crypto_hash *tfm_cmac, const u8 u[32], const u8 v[32],return 0 ; } +static int smp_h6 (struct crypto_hash *tfm_cmac,const u8 w[16 ], +const u8 key_id[4 ],u8 res[16 ]) +{ +int err; + +SMP_DBG ("w %16phN key_id %4phN" , w, key_id); + + err =aes_cmac (tfm_cmac, w, key_id,4 , res); +if (err) +return err; + +SMP_DBG ("res %16phN" , res); + +return err; +} + +/* The following functions map to the legacy SMP crypto functions e, c1, +* s1 and ah. +*/ +static int smp_e (struct crypto_blkcipher *tfm,const u8 *k,u8 *r) {struct blkcipher_desc desc;
@@ -364,18 +388,59 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)return err; } -static int smp_h6 (struct crypto_hash *tfm_cmac,const u8 w[16 ], -const u8 key_id[4 ],u8 res[16 ]) +static int smp_c1 (struct crypto_blkcipher *tfm_aes,const u8 k[16 ], +const u8 r[16 ],const u8 preq[7 ],const u8 pres[7 ],u8 _iat, +const bdaddr_t *ia,u8 _rat,const bdaddr_t *ra,u8 res[16 ]) { +u8 p1[16 ], p2[16 ];int err; -SMP_DBG ("w %16phN key_id %4phN" , w, key_id); +memset (p1,0 ,16 ); - err =aes_cmac (tfm_cmac, w, key_id,4 , res); -if (err) +/* p1 = pres || preq || _rat || _iat */ + p1[0 ] = _iat; + p1[1 ] = _rat; +memcpy (p1 +2 , preq,7 ); +memcpy (p1 +9 , pres,7 ); + +/* p2 = padding || ia || ra */ +memcpy (p2, ra,6 ); +memcpy (p2 +6 , ia,6 ); +memset (p2 +12 ,0 ,4 ); + +/* res = r XOR p1 */ +u128_xor ((u128 *) res, (u128 *) r, (u128 *) p1); + +/* res = e(k, res) */ + err =smp_e (tfm_aes, k, res); +if (err) { +BT_ERR ("Encrypt data error" );return err; + } -SMP_DBG ("res %16phN" , res); +/* res = res XOR p2 */ +u128_xor ((u128 *) res, (u128 *) res, (u128 *) p2); + +/* res = e(k, res) */ + err =smp_e (tfm_aes, k, res); +if (err) +BT_ERR ("Encrypt data error" ); + +return err; +} + +static int smp_s1 (struct crypto_blkcipher *tfm_aes,const u8 k[16 ], +const u8 r1[16 ],const u8 r2[16 ],u8 _r[16 ]) +{ +int err; + +/* Just least significant octets from r1 and r2 are considered */ +memcpy (_r, r2,8 ); +memcpy (_r +8 , r1,8 ); + + err =smp_e (tfm_aes, k, _r); +if (err) +BT_ERR ("Encrypt data error" );return err; }
@@ -454,63 +519,6 @@ int smp_generate_rpa(struct hci_dev *hdev, const u8 irk[16], bdaddr_t *rpa)return 0 ; } -static int smp_c1 (struct crypto_blkcipher *tfm_aes,const u8 k[16 ], -const u8 r[16 ],const u8 preq[7 ],const u8 pres[7 ],u8 _iat, -const bdaddr_t *ia,u8 _rat,const bdaddr_t *ra,u8 res[16 ]) -{ -u8 p1[16 ], p2[16 ]; -int err; - -memset (p1,0 ,16 ); - -/* p1 = pres || preq || _rat || _iat */ - p1[0 ] = _iat; - p1[1 ] = _rat; -memcpy (p1 +2 , preq,7 ); -memcpy (p1 +9 , pres,7 ); - -/* p2 = padding || ia || ra */ -memcpy (p2, ra,6 ); -memcpy (p2 +6 , ia,6 ); -memset (p2 +12 ,0 ,4 ); - -/* res = r XOR p1 */ -u128_xor ((u128 *) res, (u128 *) r, (u128 *) p1); - -/* res = e(k, res) */ - err =smp_e (tfm_aes, k, res); -if (err) { -BT_ERR ("Encrypt data error" ); -return err; - } - -/* res = res XOR p2 */ -u128_xor ((u128 *) res, (u128 *) res, (u128 *) p2); - -/* res = e(k, res) */ - err =smp_e (tfm_aes, k, res); -if (err) -BT_ERR ("Encrypt data error" ); - -return err; -} - -static int smp_s1 (struct crypto_blkcipher *tfm_aes,const u8 k[16 ], -const u8 r1[16 ],const u8 r2[16 ],u8 _r[16 ]) -{ -int err; - -/* Just least significant octets from r1 and r2 are considered */ -memcpy (_r, r2,8 ); -memcpy (_r +8 , r1,8 ); - - err =smp_e (tfm_aes, k, _r); -if (err) -BT_ERR ("Encrypt data error" ); - -return err; -} -static void smp_send_cmd (struct l2cap_conn *conn,u8 code,u16 len,void *data) {struct l2cap_chan *chan = conn->smp;
Signature · 1 line
2.1.0
PATCH 47/49 Bluetooth: Fix SMP debug key handling
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
We need to keep debug keys around at least until the point that they are used - otherwise e.g. slave role behavior wouldn't work as there'd be no key to be looked up. The correct behavior should therefore be to return any stored keys but when we clean up the SMP context to remove the key from the hdev list if keeping debug keys around hasn't been requestsed.
--- net/bluetooth/hci_core.c | 10 +--------- net/bluetooth/smp.c | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 11 deletions(-)
net/bluetooth/hci_core.c +1 -9
@@ -3246,15 +3246,7 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr,if (addr_type != k->bdaddr_type ||bacmp (bdaddr, &k->bdaddr))continue ; -if (smp_ltk_is_sc (k)) { -if (k->type ==SMP_LTK_P256_DEBUG && - !test_bit (HCI_KEEP_DEBUG_KEYS , &hdev->dev_flags)) -continue ; -rcu_read_unlock (); -return k; - } - -if (ltk_role (k->type) == role) { +if (smp_ltk_is_sc (k) ||ltk_role (k->type) == role) {rcu_read_unlock ();return k; }
net/bluetooth/smp.c +13 -2
@@ -670,6 +670,7 @@ static void smp_chan_destroy(struct l2cap_conn *conn) {struct l2cap_chan *chan = conn->smp;struct smp_chan *smp = chan->data; +struct hci_conn *hcon = conn->hcon;bool complete;BUG_ON (!smp);
@@ -677,7 +678,7 @@ static void smp_chan_destroy(struct l2cap_conn *conn)cancel_delayed_work_sync (&smp->security_timer); complete =test_bit (SMP_FLAG_COMPLETE , &smp->flags); -mgmt_smp_complete (conn->hcon, complete); +mgmt_smp_complete (hcon, complete);kfree (smp->csrk);kfree (smp->slave_csrk);
@@ -686,6 +687,16 @@ static void smp_chan_destroy(struct l2cap_conn *conn)crypto_free_blkcipher (smp->tfm_aes);crypto_free_hash (smp->tfm_cmac); +/* Ensure that we don't leave any debug key around if debug key +* support hasn't been explicitly enabled. +*/ +if (smp->ltk && smp->ltk->type ==SMP_LTK_P256_DEBUG && + !test_bit (HCI_KEEP_DEBUG_KEYS , &hcon->hdev->dev_flags)) { +list_del_rcu (&smp->ltk->list); +kfree_rcu (smp->ltk, rcu); + smp->ltk =NULL ; + } +/* If pairing failed clean up any keys we might have */ if (!complete) {if (smp->ltk) {
@@ -706,7 +717,7 @@ static void smp_chan_destroy(struct l2cap_conn *conn) chan->data =NULL ;kfree (smp); -hci_conn_drop (conn->hcon); +hci_conn_drop (hcon); }static void smp_failure (struct l2cap_conn *conn,u8 reason)
Signature · 1 line
2.1.0
PATCH 48/49 Bluetooth: Fix minor coding style issue in smp.c
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
The convention for checking for NULL pointers is !ptr and not ptr == NULL. This patch fixes such an occurrence in smp.c.
--- net/bluetooth/smp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/bluetooth/smp.c +1 -1
@@ -356,7 +356,7 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)uint8_t tmp[16 ], data[16 ];int err; -if (tfm ==NULL ) { +if (!tfm) {BT_ERR ("tfm %p" , tfm);return -EINVAL ; }
Signature · 1 line
2.1.0
PATCH 49/49 Bluetooth: Fix false-positive "uninitialized" compiler warning
In reply to Johan HedbergFrom: Johan Hedberg <[email protected]>
Some gcc versions don't seem to be able to properly track the flow of the smp_cmd_pairing_random() function and end up causing the following types of (false-positive) warnings:
smp.c:1995:6: warning: ‘nb’ may be used uninitialized in this function [-Wmaybe-uninitialized]
err = smp_g2(smp->tfm_cmac, pkax, pkbx, na, nb, &passkey);
smp.c:1995:6: warning: ‘na’ may be used uninitialized in this function [-Wmaybe-uninitialized]
err = smp_g2(smp->tfm_cmac, pkax, pkbx, na, nb, &passkey);
^
smp.c:1995:6: warning: ‘pkbx’ may be used uninitialized in this function [-Wmaybe-uninitialized]
err = smp_g2(smp->tfm_cmac, pkax, pkbx, na, nb, &passkey);
^ smp.c:1995:6: warning: ‘pkax’ may be used uninitialized in this function [-Wmaybe-uninitialized]
err = smp_g2(smp->tfm_cmac, pkax, pkbx, na, nb, &passkey);
This patch fixes the issue by moving the pkax/pkbx and na/nb initialization earlier in the function.
--- net/bluetooth/smp.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-)
net/bluetooth/smp.c +12 -10
@@ -1947,6 +1947,18 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)if (!test_bit (SMP_FLAG_SC , &smp->flags))return smp_random (smp); +if (hcon->out) { + pkax = smp->local_pk; + pkbx = smp->remote_pk; + na = smp->prnd; + nb = smp->rrnd; + }else { + pkax = smp->remote_pk; + pkbx = smp->local_pk; + na = smp->rrnd; + nb = smp->prnd; + } +if (smp->method ==REQ_OOB ) {if (!hcon->out) smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM,
@@ -1969,20 +1981,10 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)if (memcmp (smp->pcnf, cfm,16 ))return SMP_CONFIRM_FAILED ; - - pkax = smp->local_pk; - pkbx = smp->remote_pk; - na = smp->prnd; - nb = smp->rrnd; }else {smp_send_cmd (conn,SMP_CMD_PAIRING_RANDOM ,sizeof (smp->prnd), smp->prnd);SMP_ALLOW_CMD (smp,SMP_CMD_DHKEY_CHECK ); - - pkax = smp->remote_pk; - pkbx = smp->local_pk; - na = smp->rrnd; - nb = smp->prnd; } mackey_and_ltk:
Signature · 1 line
2.1.0
Marcel Holtmann
maintainerHi Johan,
Quoted 64 lines
First of all, appologies to all for this huge patch set. It's work from the past 6 months or so that wasn't releasable until the 4.2 specification goes public. That happened just some moments ago:
http://www.bluetooth.com/SiteCollectionDocuments/4-2/bluetooth4-2.aspx
I'm sending the patches to the mailing list mainly for reference since Marcel will probably directly merge them from my tree. Any issues/fixes etc should be done on top of them.
Johan
----------------------------------------------------------------
Johan Hedberg (49):
Bluetooth: Add basic SMP defines for LE Secure Connections
Bluetooth: Makeauth_reqmask dependent on SC enabled or not
Bluetooth: Add SMP flag for SC and set it when necessary.
Bluetooth: Update SMP security level to/fromauth_reqfor SC
Bluetooth: Add mgmt support for LE Secure Connections LTK types
Bluetooth: Set the correct security level for SC LTKs
Bluetooth: Use custom macro for testing BR/EDR SC enabled
Bluetooth: Addmgmt_set_secure_connsupport for any LE adapter
Bluetooth: Update LTK lookup to correctly deal with SC LTKs
Bluetooth: Remove unusedhci_find_ltkfunction
Bluetooth: Renamehci_find_ltk_by_addrtohci_find_ltk
Bluetooth: Set link key generation bit if necessary for LE SC
Bluetooth: Add basic support for AES-CMAC
Bluetooth: Add ECC library for LE Secure Connections
Bluetooth: Add basic support for sending our LE SC public key
Bluetooth: Add handler function for receiving LE SC public key
Bluetooth: Add support for sending LE SC Confirm value
Bluetooth: Add LE SC support for responding to Pairing Confirm PDU
Bluetooth: Add support for LE SC numeric comparison
Bluetooth: Add support for handling LE SC user response
Bluetooth: Add support for LE SC DHKey check PDU
Bluetooth: Add support for LE SC key generation
Bluetooth: Track authentication method in SMP context
Bluetooth: Add selection of the SC authentication method
Bluetooth: Detect SMP SC debug keys
Bluetooth: Add check for accidentally generating a debug key
Bluetooth: Set correct LTK type and authentication for SC
Bluetooth: Add support for SC just-works pairing
Bluetooth: Fix BR/EDR Link Key type when derived through LE SC
Bluetooth: Add passkey entry support for LE SC
Bluetooth: Fix DHKey Check sending order for slave role
Bluetooth: Add dummy handler for LE SC keypress notification
Bluetooth: Use debug keys for SMP whenHCI_USE_DEBUG_KEYSis set
Bluetooth: Addhci_connflag for new link key generation
Bluetooth: Add debugfs switch for forcing SMP over BR/EDR
Bluetooth: Add skeleton for BR/EDR SMP channel
Bluetooth: Add full SMP BR/EDR support
Bluetooth: Add SC-only mode support for SMP
Bluetooth: Unify remote OOB data functions
Bluetooth: Store address type with OOB data
Bluetooth: Add support for adding remote OOB data for LE
Bluetooth: Set SMP OOB flag if OOB data is available
Bluetooth: Add basic LE SC OOB support for remote OOB data
Bluetooth: IntroduceSMP_DBGmacro for low-level debuging
Bluetooth: Fix missing const declarations in SMP functions
Bluetooth: Organize SMP crypto functions to logical sections
Bluetooth: Fix SMP debug key handling
Bluetooth: Fix minor coding style issue insmp.c
Bluetooth: Fix false-positive "uninitialized" compiler warning
Quoted 15 lines
include/net/bluetooth/hci.h | 1 + include/net/bluetooth/hci_core.h | 23 +- include/net/bluetooth/l2cap.h | 2 + include/net/bluetooth/mgmt.h | 3 + net/bluetooth/Kconfig | 1 + net/bluetooth/Makefile | 2 +- net/bluetooth/ecc.c | 816 ++++++++++++++++++++ net/bluetooth/ecc.h | 54 ++ net/bluetooth/hci_core.c | 155 ++-- net/bluetooth/hci_event.c | 23 +- net/bluetooth/l2cap_core.c | 4 + net/bluetooth/mgmt.c | 75 +- net/bluetooth/smp.c | 1543 +++++++++++++++++++++++++++++++++---- net/bluetooth/smp.h | 51 +- 14 files changed, 2509 insertions(+), 244 deletions(-)
all 49 patches have been applied to bluetooth-next tree.
Regards
Marcel