From e491eaf3c0b02b5325535a2de3e4fa15a3093190 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 25 Oct 2014 21:15:37 +0200 Subject: Bluetooth: Pass only crypto context to SMP crypto functions In order to make unit testing possible we need to make the SMP crypto functions only take the crypto context instead of the full SMP context (the latter would require having hci_dev, hci_conn, l2cap_chan, l2cap_conn, etc around). The drawback is that we no-longer get the involved hdev in the debug logs, but this is really the only way to make simple unit tests for the code. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index f09b6b6..fea3782 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -191,16 +191,13 @@ int smp_generate_rpa(struct hci_dev *hdev, u8 irk[16], bdaddr_t *rpa) return 0; } -static int smp_c1(struct smp_chan *smp, 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, 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]) { - struct hci_dev *hdev = smp->conn->hcon->hdev; u8 p1[16], p2[16]; int err; - BT_DBG("%s", hdev->name); - memset(p1, 0, 16); /* p1 = pres || preq || _rat || _iat */ @@ -218,7 +215,7 @@ static int smp_c1(struct smp_chan *smp, u8 k[16], u8 r[16], u8 preq[7], u128_xor((u128 *) res, (u128 *) r, (u128 *) p1); /* res = e(k, res) */ - err = smp_e(smp->tfm_aes, k, res); + err = smp_e(tfm_aes, k, res); if (err) { BT_ERR("Encrypt data error"); return err; @@ -228,26 +225,23 @@ static int smp_c1(struct smp_chan *smp, u8 k[16], u8 r[16], u8 preq[7], u128_xor((u128 *) res, (u128 *) res, (u128 *) p2); /* res = e(k, res) */ - err = smp_e(smp->tfm_aes, k, res); + err = smp_e(tfm_aes, k, res); if (err) BT_ERR("Encrypt data error"); return err; } -static int smp_s1(struct smp_chan *smp, u8 k[16], u8 r1[16], u8 r2[16], - u8 _r[16]) +static int smp_s1(struct crypto_blkcipher *tfm_aes, u8 k[16], u8 r1[16], + u8 r2[16], u8 _r[16]) { - struct hci_dev *hdev = smp->conn->hcon->hdev; int err; - BT_DBG("%s", hdev->name); - /* Just least significant octets from r1 and r2 are considered */ memcpy(_r, r2, 8); memcpy(_r + 8, r1, 8); - err = smp_e(smp->tfm_aes, k, _r); + err = smp_e(tfm_aes, k, _r); if (err) BT_ERR("Encrypt data error"); @@ -547,7 +541,7 @@ static u8 smp_confirm(struct smp_chan *smp) BT_DBG("conn %p", conn); - ret = smp_c1(smp, smp->tk, smp->prnd, smp->preq, smp->prsp, + ret = smp_c1(smp->tfm_aes, smp->tk, smp->prnd, smp->preq, smp->prsp, conn->hcon->init_addr_type, &conn->hcon->init_addr, conn->hcon->resp_addr_type, &conn->hcon->resp_addr, cp.confirm_val); @@ -578,7 +572,7 @@ static u8 smp_random(struct smp_chan *smp) BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); - ret = smp_c1(smp, smp->tk, smp->rrnd, smp->preq, smp->prsp, + ret = smp_c1(smp->tfm_aes, smp->tk, smp->rrnd, smp->preq, smp->prsp, hcon->init_addr_type, &hcon->init_addr, hcon->resp_addr_type, &hcon->resp_addr, confirm); if (ret) @@ -594,7 +588,7 @@ static u8 smp_random(struct smp_chan *smp) __le64 rand = 0; __le16 ediv = 0; - smp_s1(smp, smp->tk, smp->rrnd, smp->prnd, stk); + smp_s1(smp->tfm_aes, smp->tk, smp->rrnd, smp->prnd, stk); memset(stk + smp->enc_key_size, 0, SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); @@ -613,7 +607,7 @@ static u8 smp_random(struct smp_chan *smp) smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd), smp->prnd); - smp_s1(smp, smp->tk, smp->prnd, smp->rrnd, stk); + smp_s1(smp->tfm_aes, smp->tk, smp->prnd, smp->rrnd, stk); memset(stk + smp->enc_key_size, 0, SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); -- cgit v1.1 From 4cd3362da899a59955146851dd860198b0aaaa75 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 25 Oct 2014 21:15:38 +0200 Subject: Bluetooth: Add skeleton for SMP self-tests This patch adds a basic skeleton for SMP self-tests. The tests are put behind a new configuration option since running them will slow down the boot process. For now there are no actual tests defined but those will come in a subsequent patch. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index fea3782..9821dc9 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1743,3 +1743,36 @@ void smp_unregister(struct hci_dev *hdev) hdev->smp_data = NULL; l2cap_chan_put(chan); } + +#ifdef CONFIG_BT_SELFTEST + +static int __init run_selftests(struct crypto_blkcipher *tfm_aes) +{ + return 0; +} + +static int __init test_smp(void) +{ + struct crypto_blkcipher *tfm_aes; + int err; + + tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm_aes)) { + BT_ERR("Unable to create ECB crypto context"); + return PTR_ERR(tfm_aes); + } + + err = run_selftests(tfm_aes); + if (err < 0) + BT_ERR("Self tests failed"); + else + BT_INFO("Self-tests passed"); + + crypto_free_blkcipher(tfm_aes); + + return err; +} + +module_init(test_smp); + +#endif /* CONFIG_BT_SELFTEST */ -- cgit v1.1 From c6992e9ef2a17e9738b7bb8a03a7fe581a8f9977 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 25 Oct 2014 21:15:39 +0200 Subject: Bluetooth: Add self-tests for SMP crypto functions This patch adds self-tests for the c1 and s1 crypto functions used for SMP pairing. The data used is the sample data from the core specification. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 9821dc9..983d1e0 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1746,8 +1746,95 @@ void smp_unregister(struct hci_dev *hdev) #ifdef CONFIG_BT_SELFTEST +static int __init test_ah(struct crypto_blkcipher *tfm_aes) +{ + u8 irk[16] = { 0x9b, 0x7d, 0x39, 0x0a, 0xa6, 0x10, 0x10, 0x34, + 0x05, 0xad, 0xc8, 0x57, 0xa3, 0x34, 0x02, 0xec }; + u8 r[3] = { 0x94, 0x81, 0x70 }; + u8 exp[3] = { 0xaa, 0xfb, 0x0d }; + u8 res[3]; + int err; + + err = smp_ah(tfm_aes, irk, r, res); + if (err) + return err; + + if (memcmp(res, exp, 3) != 0) + return -EINVAL; + + return 0; +} + +static int __init test_c1(struct crypto_blkcipher *tfm_aes) +{ + u8 k[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + u8 r[16] = { 0xe0, 0x2e, 0x70, 0xc6, 0x4e, 0x27, 0x88, 0x63, + 0x0e, 0x6f, 0xad, 0x56, 0x21, 0xd5, 0x83, 0x57 }; + u8 preq[7] = { 0x01, 0x01, 0x00, 0x00, 0x10, 0x07, 0x07 }; + u8 pres[7] = { 0x02, 0x03, 0x00, 0x00, 0x08, 0x00, 0x05 }; + u8 _iat = 0x01; + u8 _rat = 0x00; + bdaddr_t ra = { { 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1 } }; + bdaddr_t ia = { { 0xa6, 0xa5, 0xa4, 0xa3, 0xa2, 0xa1 } }; + u8 exp[16] = { 0x86, 0x3b, 0xf1, 0xbe, 0xc5, 0x4d, 0xa7, 0xd2, + 0xea, 0x88, 0x89, 0x87, 0xef, 0x3f, 0x1e, 0x1e }; + u8 res[16]; + int err; + + err = smp_c1(tfm_aes, k, r, preq, pres, _iat, &ia, _rat, &ra, res); + if (err) + return err; + + if (memcmp(res, exp, 16) != 0) + return -EINVAL; + + return 0; +} + +static int __init test_s1(struct crypto_blkcipher *tfm_aes) +{ + u8 k[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + u8 r1[16] = { 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11 }; + u8 r2[16] = { 0x00, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99 }; + u8 exp[16] = { 0x62, 0xa0, 0x6d, 0x79, 0xae, 0x16, 0x42, 0x5b, + 0x9b, 0xf4, 0xb0, 0xe8, 0xf0, 0xe1, 0x1f, 0x9a }; + u8 res[16]; + int err; + + err = smp_s1(tfm_aes, k, r1, r2, res); + if (err) + return err; + + if (memcmp(res, exp, 16) != 0) + return -EINVAL; + + return 0; +} + static int __init run_selftests(struct crypto_blkcipher *tfm_aes) { + int err; + + err = test_ah(tfm_aes); + if (err) { + BT_ERR("smp_ah test failed"); + return err; + } + + err = test_c1(tfm_aes); + if (err) { + BT_ERR("smp_c1 test failed"); + return err; + } + + err = test_s1(tfm_aes); + if (err) { + BT_ERR("smp_s1 test failed"); + return err; + } + return 0; } -- cgit v1.1 From da213f8e0cf03146925205b663413e4589b5b359 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 28 Oct 2014 15:22:12 +0100 Subject: Bluetooth: Revert SMP self-test patches This reverts commits c6992e9ef2a17e9738b7bb8a03a7fe581a8f9977 and 4cd3362da899a59955146851dd860198b0aaaa75. The reason for the revert is that we cannot have more than one module initialization function and the SMP one breaks the build with modular kernels. As the proper fix for this is right now looking non-trivial it's better to simply revert the problematic patches in order to keep the upstream tree compilable. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 120 ---------------------------------------------------- 1 file changed, 120 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 983d1e0..fea3782 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1743,123 +1743,3 @@ void smp_unregister(struct hci_dev *hdev) hdev->smp_data = NULL; l2cap_chan_put(chan); } - -#ifdef CONFIG_BT_SELFTEST - -static int __init test_ah(struct crypto_blkcipher *tfm_aes) -{ - u8 irk[16] = { 0x9b, 0x7d, 0x39, 0x0a, 0xa6, 0x10, 0x10, 0x34, - 0x05, 0xad, 0xc8, 0x57, 0xa3, 0x34, 0x02, 0xec }; - u8 r[3] = { 0x94, 0x81, 0x70 }; - u8 exp[3] = { 0xaa, 0xfb, 0x0d }; - u8 res[3]; - int err; - - err = smp_ah(tfm_aes, irk, r, res); - if (err) - return err; - - if (memcmp(res, exp, 3) != 0) - return -EINVAL; - - return 0; -} - -static int __init test_c1(struct crypto_blkcipher *tfm_aes) -{ - u8 k[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - u8 r[16] = { 0xe0, 0x2e, 0x70, 0xc6, 0x4e, 0x27, 0x88, 0x63, - 0x0e, 0x6f, 0xad, 0x56, 0x21, 0xd5, 0x83, 0x57 }; - u8 preq[7] = { 0x01, 0x01, 0x00, 0x00, 0x10, 0x07, 0x07 }; - u8 pres[7] = { 0x02, 0x03, 0x00, 0x00, 0x08, 0x00, 0x05 }; - u8 _iat = 0x01; - u8 _rat = 0x00; - bdaddr_t ra = { { 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1 } }; - bdaddr_t ia = { { 0xa6, 0xa5, 0xa4, 0xa3, 0xa2, 0xa1 } }; - u8 exp[16] = { 0x86, 0x3b, 0xf1, 0xbe, 0xc5, 0x4d, 0xa7, 0xd2, - 0xea, 0x88, 0x89, 0x87, 0xef, 0x3f, 0x1e, 0x1e }; - u8 res[16]; - int err; - - err = smp_c1(tfm_aes, k, r, preq, pres, _iat, &ia, _rat, &ra, res); - if (err) - return err; - - if (memcmp(res, exp, 16) != 0) - return -EINVAL; - - return 0; -} - -static int __init test_s1(struct crypto_blkcipher *tfm_aes) -{ - u8 k[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - u8 r1[16] = { 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11 }; - u8 r2[16] = { 0x00, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99 }; - u8 exp[16] = { 0x62, 0xa0, 0x6d, 0x79, 0xae, 0x16, 0x42, 0x5b, - 0x9b, 0xf4, 0xb0, 0xe8, 0xf0, 0xe1, 0x1f, 0x9a }; - u8 res[16]; - int err; - - err = smp_s1(tfm_aes, k, r1, r2, res); - if (err) - return err; - - if (memcmp(res, exp, 16) != 0) - return -EINVAL; - - return 0; -} - -static int __init run_selftests(struct crypto_blkcipher *tfm_aes) -{ - int err; - - err = test_ah(tfm_aes); - if (err) { - BT_ERR("smp_ah test failed"); - return err; - } - - err = test_c1(tfm_aes); - if (err) { - BT_ERR("smp_c1 test failed"); - return err; - } - - err = test_s1(tfm_aes); - if (err) { - BT_ERR("smp_s1 test failed"); - return err; - } - - return 0; -} - -static int __init test_smp(void) -{ - struct crypto_blkcipher *tfm_aes; - int err; - - tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(tfm_aes)) { - BT_ERR("Unable to create ECB crypto context"); - return PTR_ERR(tfm_aes); - } - - err = run_selftests(tfm_aes); - if (err < 0) - BT_ERR("Self tests failed"); - else - BT_INFO("Self-tests passed"); - - crypto_free_blkcipher(tfm_aes); - - return err; -} - -module_init(test_smp); - -#endif /* CONFIG_BT_SELFTEST */ -- cgit v1.1 From 49c922bb1ec01ac3a98e5881f6c85ea7ef52d53f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 27 Oct 2014 21:12:20 -0700 Subject: Bluetooth: spelling fixes Fix spelling errors in comments. Signed-off-by: Stephen Hemminger Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index fea3782..3ebf65b 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -964,7 +964,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) if (sec_level > conn->hcon->pending_sec_level) conn->hcon->pending_sec_level = sec_level; - /* If we need MITM check that it can be acheived */ + /* If we need MITM check that it can be achieved */ if (conn->hcon->pending_sec_level >= BT_SECURITY_HIGH) { u8 method; @@ -1022,7 +1022,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) auth = rsp->auth_req & AUTH_REQ_MASK; - /* If we need MITM check that it can be acheived */ + /* If we need MITM check that it can be achieved */ if (conn->hcon->pending_sec_level >= BT_SECURITY_HIGH) { u8 method; -- cgit v1.1 From a930430b047a0cc118bfc47ca54fcdfbadf091d2 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 12 Nov 2014 09:17:08 +0200 Subject: Bluetooth: Remove unnecessary hci_dev_lock/unlock in smp.c The mgmt_user_passkey_request and related functions do not do anything else except read access to hdev->id. This member never changes after the hdev creation so there is no need to acquire a lock to read it. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 3ebf65b..3d38553 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -514,8 +514,6 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, set_bit(SMP_FLAG_TK_VALID, &smp->flags); } - hci_dev_lock(hcon->hdev); - if (method == REQ_PASSKEY) ret = mgmt_user_passkey_request(hcon->hdev, &hcon->dst, hcon->type, hcon->dst_type); @@ -528,8 +526,6 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, hcon->type, hcon->dst_type, passkey, 0); - hci_dev_unlock(hcon->hdev); - return ret; } -- cgit v1.1 From abe84903a8efc6b83fa92161429e0e3a28bde15c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 12 Nov 2014 22:22:21 +0200 Subject: Bluetooth: Use proper nesting annotation for l2cap_chan lock By default lockdep considers all L2CAP channels equal. This would mean that we get warnings if a channel is locked when another one's lock is tried to be acquired in the same thread. This kind of inter-channel locking dependencies exist in the form of parent-child channels as well as any channel wishing to elevate the security by requesting procedures on the SMP channel. To eliminate the chance for these lockdep warnings we introduce a nesting level for each channel and use that when acquiring the channel lock. For now there exists the earlier mentioned three identified categories: SMP, "normal" channels and parent channels (i.e. those in BT_LISTEN state). The nesting level is defined as atomic_t since we need access to it before the lock is actually acquired. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 3d38553..3b63c7f 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1658,6 +1658,13 @@ static inline struct l2cap_chan *smp_new_conn_cb(struct l2cap_chan *pchan) chan->omtu = pchan->omtu; chan->mode = pchan->mode; + /* Other L2CAP channels may request SMP routines in order to + * change the security level. This means that the SMP channel + * lock must be considered in its own category to avoid lockdep + * warnings. + */ + atomic_set(&chan->nesting, L2CAP_NESTING_SMP); + BT_DBG("created chan %p", chan); return chan; @@ -1715,6 +1722,9 @@ int smp_register(struct hci_dev *hdev) chan->imtu = L2CAP_DEFAULT_MTU; chan->ops = &smp_root_chan_ops; + /* Set correct nesting level for a parent/listening channel */ + atomic_set(&chan->nesting, L2CAP_NESTING_PARENT); + hdev->smp_data = chan; return 0; -- cgit v1.1 From 35dc6f834c9dc888391c7b700130d0831a907ca1 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 13 Nov 2014 10:55:18 +0200 Subject: Bluetooth: Add key preference parameter to smp_sufficient_security So far smp_sufficient_security() has returned false if we're encrypted with an STK but do have an LTK available. However, for the sake of LE CoC servers we do want to let the incoming connection through even though we're only encrypted with the STK. This patch adds a key preference parameter to smp_sufficient_security() with two possible values (enum used instead of bool for readability). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 3b63c7f..3dc5f0e 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1122,18 +1122,20 @@ static bool smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level) return true; } -bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level) +bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level, + enum smp_key_pref key_pref) { if (sec_level == BT_SECURITY_LOW) return true; - /* If we're encrypted with an STK always claim insufficient - * security. This way we allow the connection to be re-encrypted - * with an LTK, even if the LTK provides the same level of - * security. Only exception is if we don't have an LTK (e.g. - * because of key distribution bits). + /* If we're encrypted with an STK but the caller prefers using + * LTK claim insufficient security. This way we allow the + * connection to be re-encrypted with an LTK, even if the LTK + * provides the same level of security. Only exception is if we + * don't have an LTK (e.g. because of key distribution bits). */ - if (test_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags) && + 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)) return false; @@ -1167,7 +1169,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) else sec_level = authreq_to_seclevel(auth); - if (smp_sufficient_security(hcon, sec_level)) + if (smp_sufficient_security(hcon, sec_level, SMP_USE_LTK)) return 0; if (sec_level > hcon->pending_sec_level) @@ -1217,7 +1219,7 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags)) return 1; - if (smp_sufficient_security(hcon, sec_level)) + if (smp_sufficient_security(hcon, sec_level, SMP_USE_LTK)) return 1; if (sec_level > hcon->pending_sec_level) -- cgit v1.1 From 970d0f1b280372cfd46b6de5529d96f8448de943 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 13 Nov 2014 14:37:47 +0200 Subject: Bluetooth: Convert LTK list to RCU This patch set converts the hdev->long_term_keys list to use RCU to eliminate the need to use hci_dev_lock/unlock. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 3dc5f0e..fd2dfe5 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -383,13 +383,13 @@ static void smp_chan_destroy(struct l2cap_conn *conn) /* If pairing failed clean up any keys we might have */ if (!complete) { if (smp->ltk) { - list_del(&smp->ltk->list); - kfree(smp->ltk); + list_del_rcu(&smp->ltk->list); + kfree_rcu(smp->ltk, rcu); } if (smp->slave_ltk) { - list_del(&smp->slave_ltk->list); - kfree(smp->slave_ltk); + list_del_rcu(&smp->slave_ltk->list); + kfree_rcu(smp->slave_ltk, rcu); } if (smp->remote_irk) { @@ -1321,7 +1321,6 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) skb_pull(skb, sizeof(*rp)); - hci_dev_lock(hdev); authenticated = (hcon->sec_level == BT_SECURITY_HIGH); ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, SMP_LTK, authenticated, smp->tk, smp->enc_key_size, @@ -1329,7 +1328,6 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) smp->ltk = ltk; if (!(smp->remote_key_dist & KEY_DIST_MASK)) smp_distribute_keys(smp); - hci_dev_unlock(hdev); return 0; } -- cgit v1.1 From adae20cb2d20e5151b866945f802b0c2312f0f82 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 13 Nov 2014 14:37:48 +0200 Subject: Bluetooth: Convert IRK list to RCU This patch set converts the hdev->identity_resolving_keys list to use RCU to eliminate the need to use hci_dev_lock/unlock. An additional change that must be done is to remove use of CRYPTO_ALG_ASYNC for the hdev-specific AES crypto context. The reason is that this context is used for matching RPAs and the loop that does the matching is under the RCU read lock, i.e. is an atomic section which cannot sleep. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index fd2dfe5..7b610f6 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -393,8 +393,8 @@ static void smp_chan_destroy(struct l2cap_conn *conn) } if (smp->remote_irk) { - list_del(&smp->remote_irk->list); - kfree(smp->remote_irk); + list_del_rcu(&smp->remote_irk->list); + kfree_rcu(smp->remote_irk, rcu); } } @@ -655,8 +655,8 @@ static void smp_notify_keys(struct l2cap_conn *conn) * just remove it. */ if (!bacmp(&smp->remote_irk->rpa, BDADDR_ANY)) { - list_del(&smp->remote_irk->list); - kfree(smp->remote_irk); + list_del_rcu(&smp->remote_irk->list); + kfree_rcu(smp->remote_irk, rcu); smp->remote_irk = NULL; } } @@ -1696,7 +1696,7 @@ int smp_register(struct hci_dev *hdev) BT_DBG("%s", hdev->name); - tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC); + tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, 0); if (IS_ERR(tfm_aes)) { int err = PTR_ERR(tfm_aes); BT_ERR("Unable to create crypto context"); -- cgit v1.1 From d88b5bbf1a985c338967f3c41351b32b747a55fe Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 13 Nov 2014 14:37:49 +0200 Subject: Bluetooth: Remove unnecessary hdev locking in smp.c Now that the SMP related key lists are converted to RCU there is nothing in smp_cmd_sign_info() or smp_cmd_ident_addr_info() that would require taking the hdev lock (including the smp_distribute_keys call). This patch removes this unnecessary locking. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 7b610f6..069b76e 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1374,8 +1374,6 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, skb_pull(skb, sizeof(*info)); - hci_dev_lock(hcon->hdev); - /* Strictly speaking the Core Specification (4.1) allows sending * an empty address which would force us to rely on just the IRK * as "identity information". However, since such @@ -1403,8 +1401,6 @@ distribute: if (!(smp->remote_key_dist & KEY_DIST_MASK)) smp_distribute_keys(smp); - hci_dev_unlock(hcon->hdev); - return 0; } @@ -1413,7 +1409,6 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb) struct smp_cmd_sign_info *rp = (void *) skb->data; struct l2cap_chan *chan = conn->smp; struct smp_chan *smp = chan->data; - struct hci_dev *hdev = conn->hcon->hdev; struct smp_csrk *csrk; BT_DBG("conn %p", conn); @@ -1426,7 +1421,6 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb) skb_pull(skb, sizeof(*rp)); - hci_dev_lock(hdev); csrk = kzalloc(sizeof(*csrk), GFP_KERNEL); if (csrk) { csrk->master = 0x01; @@ -1434,7 +1428,6 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb) } smp->csrk = csrk; smp_distribute_keys(smp); - hci_dev_unlock(hdev); return 0; } -- cgit v1.1 From 0edb14de5606e145d14ae218103030269abcc152 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 26 May 2014 13:29:28 +0300 Subject: Bluetooth: Make auth_req mask dependent on SC enabled or not 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 069b76e..bfa839e 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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 0x07 enum { 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; -- cgit v1.1 From 656687769487b736674f111b92cef6ba6a31dea6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 16 May 2014 11:03:34 +0300 Subject: Bluetooth: Add SMP flag for SC and set it when necessary. 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index bfa839e..3808ade 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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; -- cgit v1.1 From d2eb9e10f74fc1fe5e7e7abc9965ff965e1b4f54 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 16 May 2014 10:59:06 +0300 Subject: Bluetooth: Update SMP security level to/from auth_req for SC 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 3808ade..4ecbf27 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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. */ -- cgit v1.1 From f3a73d97b3b78584e111478d07dfd063453f112e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 29 May 2014 15:02:59 +0300 Subject: Bluetooth: Rename hci_find_ltk_by_addr to hci_find_ltk 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 4ecbf27..0973e37 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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) -- cgit v1.1 From df8e1a4c7339f6447e75430e7c8172deddb489a9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 6 Jun 2014 10:39:56 +0300 Subject: Bluetooth: Set link key generation bit if necessary for LE SC 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 0973e37..d993d7d 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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; -- cgit v1.1 From 407cecf6c71e13da04f6b591bdbec76ab9a251c2 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 2 May 2014 14:19:47 +0300 Subject: Bluetooth: Add basic support for AES-CMAC 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index d993d7d..4fed367 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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; -- cgit v1.1 From 3b19146d23884172fe9d05f90924d4da3cdeb468 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 6 Jun 2014 10:50:15 +0300 Subject: Bluetooth: Add basic support for sending our LE SC public key 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). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 4fed367..9317583 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -29,10 +29,14 @@ #include #include +#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); -- cgit v1.1 From d8f8edbe93979bdf1f74cd768e68c7705806f0b9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 6 Jun 2014 11:09:28 +0300 Subject: Bluetooth: Add handler function for receiving LE SC public key 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 9317583..1cc438c 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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; -- cgit v1.1 From cbbbe3e242f5629fd34836e7e41737235c049ce2 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 6 Jun 2014 11:30:08 +0300 Subject: Bluetooth: Add support for sending LE SC Confirm value 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 1cc438c..0980b86 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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, (int) 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; } -- cgit v1.1 From dcee2b32216ffa62195cac394d50fd801b51a41c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 6 Jun 2014 11:36:38 +0300 Subject: Bluetooth: Add LE SC support for responding to Pairing Confirm PDU 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 Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 0980b86..6207f32 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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); -- cgit v1.1 From 191dc7fe2d3a8dde70b37a1fd086a32c1f4e1dcf Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 6 Jun 2014 11:39:49 +0300 Subject: Bluetooth: Add support for LE SC numeric comparison 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 6207f32..103f05a 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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) -- cgit v1.1 From 760b018b6cf08ee16fed37249a0a0d52d930c356 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 6 Jun 2014 11:44:05 +0300 Subject: Bluetooth: Add support for handling LE SC user response 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 103f05a..b12f076 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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; -- cgit v1.1 From 6433a9a2c47e5b3ddfdb86ee5b57a6eada1f6da7 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 6 Jun 2014 11:47:30 +0300 Subject: Bluetooth: Add support for LE SC DHKey check PDU 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index b12f076..f59f051 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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; -- cgit v1.1 From 6a77083af57f2dc515a01c8ec82610ab0e7baa59 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 6 Jun 2014 11:54:04 +0300 Subject: Bluetooth: Add support for LE SC key generation 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index f59f051..20fa07a 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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) { -- cgit v1.1 From 783e057462d514441fbd371bbb398cf886fe3376 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 31 May 2014 18:48:26 +0300 Subject: Bluetooth: Track authentication method in SMP context 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 20fa07a..45e527d 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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); -- cgit v1.1 From 5e3d3d9b3c0119e6ac86bf77c6ff9f6b0d09bcf5 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 31 May 2014 18:51:02 +0300 Subject: Bluetooth: Add selection of the SC authentication method This patch adds code to select the authentication method for Secure Connections based on the local and remote capabilities. A new DSP_PASSKEY method is also added for displaying the passkey - something that is not part of legacy SMP pairing. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 5 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 45e527d..9e11931 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -661,6 +661,7 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason) #define REQ_PASSKEY 0x02 #define CFM_PASSKEY 0x03 #define REQ_OOB 0x04 +#define DSP_PASSKEY 0x05 #define OVERLAP 0xFF static const u8 gen_method[5][5] = { @@ -671,6 +672,14 @@ static const u8 gen_method[5][5] = { { CFM_PASSKEY, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, OVERLAP }, }; +static const u8 sc_method[5][5] = { + { JUST_WORKS, JUST_CFM, REQ_PASSKEY, JUST_WORKS, REQ_PASSKEY }, + { JUST_WORKS, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, CFM_PASSKEY }, + { DSP_PASSKEY, DSP_PASSKEY, REQ_PASSKEY, JUST_WORKS, DSP_PASSKEY }, + { JUST_WORKS, JUST_CFM, JUST_WORKS, JUST_WORKS, JUST_CFM }, + { DSP_PASSKEY, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, CFM_PASSKEY }, +}; + static u8 get_auth_method(struct smp_chan *smp, u8 local_io, u8 remote_io) { /* If either side has unknown io_caps, use JUST_CFM (which gets @@ -680,6 +689,9 @@ static u8 get_auth_method(struct smp_chan *smp, u8 local_io, u8 remote_io) remote_io > SMP_IO_KEYBOARD_DISPLAY) return JUST_CFM; + if (test_bit(SMP_FLAG_SC, &smp->flags)) + return sc_method[remote_io][local_io]; + return gen_method[remote_io][local_io]; } @@ -1305,6 +1317,11 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) memcpy(&smp->preq[1], req, sizeof(*req)); skb_pull(skb, sizeof(*req)); + build_pairing_cmd(conn, req, &rsp, auth); + + if (rsp.auth_req & SMP_AUTH_SC) + set_bit(SMP_FLAG_SC, &smp->flags); + if (conn->hcon->io_capability == HCI_IO_NO_INPUT_OUTPUT) sec_level = BT_SECURITY_MEDIUM; else @@ -1323,11 +1340,6 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) return SMP_AUTH_REQUIREMENTS; } - build_pairing_cmd(conn, req, &rsp, auth); - - if (rsp.auth_req & SMP_AUTH_SC) - set_bit(SMP_FLAG_SC, &smp->flags); - key_size = min(req->max_key_size, rsp.max_key_size); if (check_enc_key_size(conn, key_size)) return SMP_ENC_KEY_SIZE; @@ -1901,12 +1913,54 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb) return 0; } +static u8 sc_select_method(struct smp_chan *smp) +{ + struct l2cap_conn *conn = smp->conn; + struct hci_conn *hcon = conn->hcon; + struct smp_cmd_pairing *local, *remote; + u8 local_mitm, remote_mitm, local_io, remote_io, method; + + /* The preq/prsp contain the raw Pairing Request/Response PDUs + * which are needed as inputs to some crypto functions. To get + * the "struct smp_cmd_pairing" from them we need to skip the + * first byte which contains the opcode. + */ + if (hcon->out) { + local = (void *) &smp->preq[1]; + remote = (void *) &smp->prsp[1]; + } else { + local = (void *) &smp->prsp[1]; + remote = (void *) &smp->preq[1]; + } + + local_io = local->io_capability; + remote_io = remote->io_capability; + + local_mitm = (local->auth_req & SMP_AUTH_MITM); + remote_mitm = (remote->auth_req & SMP_AUTH_MITM); + + /* If either side wants MITM, look up the method from the table, + * otherwise use JUST WORKS. + */ + if (local_mitm || remote_mitm) + method = get_auth_method(smp, local_io, remote_io); + else + method = JUST_WORKS; + + /* Don't confirm locally initiated pairing attempts */ + if (method == JUST_CFM && test_bit(SMP_FLAG_INITIATOR, &smp->flags)) + method = JUST_WORKS; + + return method; +} + static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_public_key *key = (void *) skb->data; struct hci_conn *hcon = conn->hcon; struct l2cap_chan *chan = conn->smp; struct smp_chan *smp = chan->data; + struct hci_dev *hdev = hcon->hdev; struct smp_cmd_pairing_confirm cfm; int err; @@ -1936,6 +1990,16 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb) set_bit(SMP_FLAG_REMOTE_PK, &smp->flags); + smp->method = sc_select_method(smp); + + BT_DBG("%s selected method 0x%02x", hdev->name, smp->method); + + /* JUST_WORKS and JUST_CFM result in an unauthenticated key */ + if (smp->method == JUST_WORKS || smp->method == JUST_CFM) + hcon->pending_sec_level = BT_SECURITY_MEDIUM; + else + hcon->pending_sec_level = BT_SECURITY_FIPS; + /* The Initiating device waits for the non-initiating device to * send the confirm value. */ -- cgit v1.1 From aeb7d461f9c895bb6d09e9d175696849e9f290c8 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 31 May 2014 18:52:28 +0300 Subject: Bluetooth: Detect SMP SC debug keys 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 9e11931..ddc76cf 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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. */ -- cgit v1.1 From 6c0dcc5014caeb9c39db816a7e0169255923ccba Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 6 Jun 2014 15:33:30 +0300 Subject: Bluetooth: Add check for accidentally generating a debug key 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index ddc76cf..63d5ba7 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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]); -- cgit v1.1 From d378a2d77618464f511d35687bbbc6614b1bacda Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 31 May 2014 18:53:36 +0300 Subject: Bluetooth: Set correct LTK type and authentication for SC After generating the LTK we should set the correct type (normal SC or debug) and authentication information for it. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 63d5ba7..3043936 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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) { -- cgit v1.1 From dddd3059e3bdd02c4850b14b925b3bb37c23f248 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 1 Jun 2014 15:38:09 +0300 Subject: Bluetooth: Add support for SC just-works pairing 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 3043936..b6cdb55 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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); -- cgit v1.1 From e3befab970a0230a80f7732fd59bc19df26f805f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 1 Jun 2014 16:33:39 +0300 Subject: Bluetooth: Fix BR/EDR Link Key type when derived through LE SC 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index b6cdb55..a322019 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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); + } + } } } -- cgit v1.1 From 38606f1418cc9c0ac4230f4d9133a2cae5e02416 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 25 Jun 2014 11:10:28 +0300 Subject: Bluetooth: Add passkey entry support for LE SC 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 191 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 180 insertions(+), 11 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index a322019..8cfa1c1 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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) -- cgit v1.1 From d3e54a876e35120b3355e22d78861e73a6acab6f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 4 Jun 2014 11:07:40 +0300 Subject: Bluetooth: Fix DHKey Check sending order for slave role According to the LE SC specification the initiating device sends its DHKey check first and the non-initiating devices sends its DHKey check as a response to this. It's also important that the non-initiating device doesn't send the response if it's still waiting for user input. In order to synchronize all this a new flag is added. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 60 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 17 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 8cfa1c1..9a4ce45 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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); -- cgit v1.1 From 1408bb6efb04da3efdc998df1bc032c1d86d1842 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 4 Jun 2014 22:45:57 +0300 Subject: Bluetooth: Add dummy handler for LE SC keypress notification 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 9a4ce45..918ce03 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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; -- cgit v1.1 From 70157ef5391819a55bb4186c901ac873231fb6ea Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 24 Jun 2014 15:22:59 +0300 Subject: Bluetooth: Use debug keys for SMP when HCI_USE_DEBUG_KEYS is set 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 918ce03..7791604 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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); -- cgit v1.1 From ef8efe4bf8b5fe1a9342ae964c428aed1be7863b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 13 Aug 2014 15:12:32 +0300 Subject: Bluetooth: Add skeleton for BR/EDR SMP channel This patch adds the very basic code for creating and destroying SMP L2CAP channels for BR/EDR connections. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 89 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 71 insertions(+), 18 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 7791604..135e725 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -2504,6 +2504,9 @@ static void smp_resume_cb(struct l2cap_chan *chan) BT_DBG("chan %p", chan); + if (hcon->type == ACL_LINK) + return; + if (!smp) return; @@ -2527,10 +2530,14 @@ static void smp_ready_cb(struct l2cap_chan *chan) static int smp_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) { + struct hci_conn *hcon = chan->conn->hcon; int err; BT_DBG("chan %p", chan); + if (hcon->type == ACL_LINK) + return -EOPNOTSUPP; + err = smp_sig_channel(chan, skb); if (err) { struct smp_chan *smp = chan->data; @@ -2627,34 +2634,40 @@ static const struct l2cap_ops smp_root_chan_ops = { .memcpy_fromiovec = l2cap_chan_no_memcpy_fromiovec, }; -int smp_register(struct hci_dev *hdev) +static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid) { struct l2cap_chan *chan; struct crypto_blkcipher *tfm_aes; - BT_DBG("%s", hdev->name); + if (cid == L2CAP_CID_SMP_BREDR) { + tfm_aes = NULL; + goto create_chan; + } tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, 0); if (IS_ERR(tfm_aes)) { - int err = PTR_ERR(tfm_aes); BT_ERR("Unable to create crypto context"); - return err; + return ERR_PTR(PTR_ERR(tfm_aes)); } +create_chan: chan = l2cap_chan_create(); if (!chan) { crypto_free_blkcipher(tfm_aes); - return -ENOMEM; + return ERR_PTR(-ENOMEM); } chan->data = tfm_aes; - l2cap_add_scid(chan, L2CAP_CID_SMP); + l2cap_add_scid(chan, cid); l2cap_chan_set_defaults(chan); bacpy(&chan->src, &hdev->bdaddr); - chan->src_type = BDADDR_LE_PUBLIC; + if (cid == L2CAP_CID_SMP) + chan->src_type = BDADDR_LE_PUBLIC; + else + chan->src_type = BDADDR_BREDR; chan->state = BT_LISTEN; chan->mode = L2CAP_MODE_BASIC; chan->imtu = L2CAP_DEFAULT_MTU; @@ -2663,20 +2676,14 @@ int smp_register(struct hci_dev *hdev) /* Set correct nesting level for a parent/listening channel */ atomic_set(&chan->nesting, L2CAP_NESTING_PARENT); - hdev->smp_data = chan; - - return 0; + return chan; } -void smp_unregister(struct hci_dev *hdev) +static void smp_del_chan(struct l2cap_chan *chan) { - struct l2cap_chan *chan = hdev->smp_data; - struct crypto_blkcipher *tfm_aes; - - if (!chan) - return; + struct crypto_blkcipher *tfm_aes; - BT_DBG("%s chan %p", hdev->name, chan); + BT_DBG("chan %p", chan); tfm_aes = chan->data; if (tfm_aes) { @@ -2684,6 +2691,52 @@ void smp_unregister(struct hci_dev *hdev) crypto_free_blkcipher(tfm_aes); } - hdev->smp_data = NULL; l2cap_chan_put(chan); } + +int smp_register(struct hci_dev *hdev) +{ + struct l2cap_chan *chan; + + BT_DBG("%s", hdev->name); + + chan = smp_add_cid(hdev, L2CAP_CID_SMP); + if (IS_ERR(chan)) + return PTR_ERR(chan); + + hdev->smp_data = chan; + + if (!lmp_sc_capable(hdev) && + !test_bit(HCI_FORCE_LESC, &hdev->dbg_flags)) + return 0; + + chan = smp_add_cid(hdev, L2CAP_CID_SMP_BREDR); + if (IS_ERR(chan)) { + int err = PTR_ERR(chan); + chan = hdev->smp_data; + hdev->smp_data = NULL; + smp_del_chan(chan); + return err; + } + + hdev->smp_bredr_data = chan; + + return 0; +} + +void smp_unregister(struct hci_dev *hdev) +{ + struct l2cap_chan *chan; + + if (hdev->smp_bredr_data) { + chan = hdev->smp_bredr_data; + hdev->smp_bredr_data = NULL; + smp_del_chan(chan); + } + + if (hdev->smp_data) { + chan = hdev->smp_data; + hdev->smp_data = NULL; + smp_del_chan(chan); + } +} -- cgit v1.1 From b5ae344d4c0f69ae6526565b55d52b64bc127087 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 14 Aug 2014 12:34:26 +0300 Subject: Bluetooth: Add full SMP BR/EDR support 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 230 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 208 insertions(+), 22 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 135e725..2c6edf1 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -915,11 +915,13 @@ static void smp_notify_keys(struct l2cap_conn *conn) mgmt_new_irk(hdev, smp->remote_irk); /* Now that user space can be considered to know the * identity address track the connection based on it - * from now on. + * from now on (assuming this is an LE link). */ - bacpy(&hcon->dst, &smp->remote_irk->bdaddr); - hcon->dst_type = smp->remote_irk->addr_type; - queue_work(hdev->workqueue, &conn->id_addr_update_work); + if (hcon->type == LE_LINK) { + bacpy(&hcon->dst, &smp->remote_irk->bdaddr); + hcon->dst_type = smp->remote_irk->addr_type; + queue_work(hdev->workqueue, &conn->id_addr_update_work); + } /* When receiving an indentity resolving key for * a remote device that does not use a resolvable @@ -938,10 +940,20 @@ static void smp_notify_keys(struct l2cap_conn *conn) } } - /* The LTKs and CSRKs should be persistent only if both sides - * had the bonding bit set in their authentication requests. - */ - persistent = !!((req->auth_req & rsp->auth_req) & SMP_AUTH_BONDING); + if (hcon->type == ACL_LINK) { + if (hcon->key_type == HCI_LK_DEBUG_COMBINATION) + persistent = false; + else + persistent = !test_bit(HCI_CONN_FLUSH_KEY, + &hcon->flags); + } else { + /* The LTKs and CSRKs should be persistent only if both sides + * had the bonding bit set in their authentication requests. + */ + persistent = !!((req->auth_req & rsp->auth_req) & + SMP_AUTH_BONDING); + } + if (smp->csrk) { smp->csrk->bdaddr_type = hcon->dst_type; @@ -1057,6 +1069,35 @@ static void smp_allow_key_dist(struct smp_chan *smp) SMP_ALLOW_CMD(smp, SMP_CMD_SIGN_INFO); } +static void sc_generate_ltk(struct smp_chan *smp) +{ + /* These constants are as specified in the core specification. + * In ASCII they spell out to 'tmp2' and 'brle'. + */ + const u8 tmp2[4] = { 0x32, 0x70, 0x6d, 0x74 }; + const u8 brle[4] = { 0x65, 0x6c, 0x72, 0x62 }; + struct hci_conn *hcon = smp->conn->hcon; + struct hci_dev *hdev = hcon->hdev; + struct link_key *key; + + key = hci_find_link_key(hdev, &hcon->dst); + if (!key) { + BT_ERR("%s No Link Key found to generate LTK", hdev->name); + return; + } + + if (key->type == HCI_LK_DEBUG_COMBINATION) + set_bit(SMP_FLAG_DEBUG_KEY, &smp->flags); + + if (smp_h6(smp->tfm_cmac, key->val, tmp2, smp->tk)) + return; + + if (smp_h6(smp->tfm_cmac, smp->tk, brle, smp->tk)) + return; + + sc_add_ltk(smp); +} + static void smp_distribute_keys(struct smp_chan *smp) { struct smp_cmd_pairing *req, *rsp; @@ -1086,8 +1127,10 @@ static void smp_distribute_keys(struct smp_chan *smp) } if (test_bit(SMP_FLAG_SC, &smp->flags)) { - if (*keydist & SMP_DIST_LINK_KEY) + if (hcon->type == LE_LINK && (*keydist & SMP_DIST_LINK_KEY)) sc_generate_link_key(smp); + if (hcon->type == ACL_LINK && (*keydist & SMP_DIST_ENC_KEY)) + sc_generate_ltk(smp); /* Clear the keys which are generated but not distributed */ *keydist &= ~SMP_SC_NO_DIST; @@ -1493,6 +1536,46 @@ unlock: return err; } +static void build_bredr_pairing_cmd(struct smp_chan *smp, + struct smp_cmd_pairing *req, + struct smp_cmd_pairing *rsp) +{ + struct l2cap_conn *conn = smp->conn; + struct hci_dev *hdev = conn->hcon->hdev; + u8 local_dist = 0, remote_dist = 0; + + if (test_bit(HCI_BONDABLE, &hdev->dev_flags)) { + local_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN; + remote_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN; + } + + if (test_bit(HCI_RPA_RESOLVING, &hdev->dev_flags)) + remote_dist |= SMP_DIST_ID_KEY; + + if (test_bit(HCI_PRIVACY, &hdev->dev_flags)) + local_dist |= SMP_DIST_ID_KEY; + + if (!rsp) { + memset(req, 0, sizeof(*req)); + + req->init_key_dist = local_dist; + req->resp_key_dist = remote_dist; + req->max_key_size = SMP_MAX_ENC_KEY_SIZE; + + smp->remote_key_dist = remote_dist; + + return; + } + + memset(rsp, 0, sizeof(*rsp)); + + 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; + + smp->remote_key_dist = rsp->init_key_dist; +} + static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_pairing rsp, *req = (void *) skb->data; @@ -1529,6 +1612,31 @@ 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)); + /* SMP over BR/EDR requires special treatment */ + if (conn->hcon->type == ACL_LINK) { + /* We must have a BR/EDR SC link */ + if (!test_bit(HCI_CONN_AES_CCM, &conn->hcon->flags)) + return SMP_CROSS_TRANSP_NOT_ALLOWED; + + set_bit(SMP_FLAG_SC, &smp->flags); + + build_bredr_pairing_cmd(smp, req, &rsp); + + key_size = min(req->max_key_size, rsp.max_key_size); + if (check_enc_key_size(conn, key_size)) + return SMP_ENC_KEY_SIZE; + + /* Clear bits which are generated but not distributed */ + smp->remote_key_dist &= ~SMP_SC_NO_DIST; + + smp->prsp[0] = SMP_CMD_PAIRING_RSP; + memcpy(&smp->prsp[1], &rsp, sizeof(rsp)); + smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp); + + smp_distribute_keys(smp); + return 0; + } + build_pairing_cmd(conn, req, &rsp, auth); if (rsp.auth_req & SMP_AUTH_SC) @@ -1644,6 +1752,22 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) auth = rsp->auth_req & AUTH_REQ_MASK(hdev); + smp->prsp[0] = SMP_CMD_PAIRING_RSP; + memcpy(&smp->prsp[1], rsp, sizeof(*rsp)); + + /* Update remote key distribution in case the remote cleared + * some bits that we had enabled in our request. + */ + smp->remote_key_dist &= rsp->resp_key_dist; + + /* For BR/EDR this means we're done and can start phase 3 */ + if (conn->hcon->type == ACL_LINK) { + /* Clear bits which are generated but not distributed */ + smp->remote_key_dist &= ~SMP_SC_NO_DIST; + smp_distribute_keys(smp); + return 0; + } + 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) @@ -1661,9 +1785,6 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) get_random_bytes(smp->prnd, sizeof(smp->prnd)); - smp->prsp[0] = SMP_CMD_PAIRING_RSP; - memcpy(&smp->prsp[1], rsp, sizeof(*rsp)); - /* Update remote key distribution in case the remote cleared * some bits that we had enabled in our request. */ @@ -2373,11 +2494,6 @@ static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb) __u8 code, reason; int err = 0; - if (hcon->type != LE_LINK) { - kfree_skb(skb); - return 0; - } - if (skb->len < 1) return -EILSEQ; @@ -2496,6 +2612,74 @@ static void smp_teardown_cb(struct l2cap_chan *chan, int err) l2cap_chan_put(chan); } +static void bredr_pairing(struct l2cap_chan *chan) +{ + struct l2cap_conn *conn = chan->conn; + struct hci_conn *hcon = conn->hcon; + struct hci_dev *hdev = hcon->hdev; + struct smp_cmd_pairing req; + struct smp_chan *smp; + + BT_DBG("chan %p", chan); + + /* Only new pairings are interesting */ + if (!test_bit(HCI_CONN_NEW_LINK_KEY, &hcon->flags)) + return; + + /* Don't bother if we're not encrypted */ + if (!test_bit(HCI_CONN_ENCRYPT, &hcon->flags)) + return; + + /* Only master may initiate SMP over BR/EDR */ + if (hcon->role != HCI_ROLE_MASTER) + return; + + /* Secure Connections support must be enabled */ + if (!test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) + return; + + /* BR/EDR must use Secure Connections for SMP */ + if (!test_bit(HCI_CONN_AES_CCM, &hcon->flags) && + !test_bit(HCI_FORCE_LESC, &hdev->dbg_flags)) + return; + + /* If our LE support is not enabled don't do anything */ + if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) + return; + + /* Don't bother if remote LE support is not enabled */ + if (!lmp_host_le_capable(hcon)) + return; + + /* Remote must support SMP fixed chan for BR/EDR */ + if (!(conn->remote_fixed_chan & L2CAP_FC_SMP_BREDR)) + return; + + /* Don't bother if SMP is already ongoing */ + if (chan->data) + return; + + smp = smp_chan_create(conn); + if (!smp) { + BT_ERR("%s unable to create SMP context for BR/EDR", + hdev->name); + return; + } + + set_bit(SMP_FLAG_SC, &smp->flags); + + BT_DBG("%s starting SMP over BR/EDR", hdev->name); + + /* Prepare and send the BR/EDR SMP Pairing Request */ + build_bredr_pairing_cmd(smp, &req, NULL); + + smp->preq[0] = SMP_CMD_PAIRING_REQ; + memcpy(&smp->preq[1], &req, sizeof(req)); + + smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(req), &req); + SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RSP); +} + static void smp_resume_cb(struct l2cap_chan *chan) { struct smp_chan *smp = chan->data; @@ -2504,8 +2688,10 @@ static void smp_resume_cb(struct l2cap_chan *chan) BT_DBG("chan %p", chan); - if (hcon->type == ACL_LINK) + if (hcon->type == ACL_LINK) { + bredr_pairing(chan); return; + } if (!smp) return; @@ -2521,23 +2707,23 @@ static void smp_resume_cb(struct l2cap_chan *chan) static void smp_ready_cb(struct l2cap_chan *chan) { struct l2cap_conn *conn = chan->conn; + struct hci_conn *hcon = conn->hcon; BT_DBG("chan %p", chan); conn->smp = chan; l2cap_chan_hold(chan); + + if (hcon->type == ACL_LINK && test_bit(HCI_CONN_ENCRYPT, &hcon->flags)) + bredr_pairing(chan); } static int smp_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) { - struct hci_conn *hcon = chan->conn->hcon; int err; BT_DBG("chan %p", chan); - if (hcon->type == ACL_LINK) - return -EOPNOTSUPP; - err = smp_sig_channel(chan, skb); if (err) { struct smp_chan *smp = chan->data; -- cgit v1.1 From 903b71c78d56af56a5f4d53a8dbef8032d1949bf Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 8 Sep 2014 16:59:18 -0700 Subject: Bluetooth: Add SC-only mode support for SMP 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 2c6edf1..589e015 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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 -- cgit v1.1 From 02b05bd8b0a632e9a26795bced8f19ca6a5f7079 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 26 Oct 2014 21:19:10 +0100 Subject: Bluetooth: Set SMP OOB flag if OOB data is available 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 589e015..0c2214a 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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; -- cgit v1.1 From a29b073351ffdda0ce9745f3bd98f5a513c523d7 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 28 Oct 2014 15:17:05 +0100 Subject: Bluetooth: Add basic LE SC OOB support for remote OOB data 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 0c2214a..059a3da 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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); -- cgit v1.1 From c7a3d57db67ce7524c72ecb33f82c099f270a109 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 1 Dec 2014 22:03:16 +0200 Subject: Bluetooth: Introduce SMP_DBG macro for low-level debuging 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 68 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 28 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 059a3da..13b40e8 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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, (int) len, m); - BT_DBG("key %16phN", k); + SMP_DBG("msg (len %zu) %*phN", len, (int) 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); -- cgit v1.1 From cd0827976205f842cc722f48a1427c9b77c3ca28 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 2 Dec 2014 13:37:41 +0200 Subject: Bluetooth: Fix missing const declarations in SMP functions Several SMP functions take read-only data. This patch fixes the declaration of these parameters to use the const specifier as appropriate. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 13b40e8..f845dbf 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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; -- cgit v1.1 From 06edf8deb55dbdcda2177da31d75ac79ccdc5841 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 2 Dec 2014 13:39:23 +0200 Subject: Bluetooth: Organize SMP crypto functions to logical sections 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 134 ++++++++++++++++++++++++++++------------------------ 1 file changed, 71 insertions(+), 63 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index f845dbf..1d1c33d 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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; -- cgit v1.1 From 923e24143efe654553cabdb08f369d3789413147 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 3 Dec 2014 12:43:39 +0200 Subject: Bluetooth: Fix SMP debug key handling 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 1d1c33d..a7b973b 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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) -- cgit v1.1 From 7f376cd6dc1c9bfd14514c70765e6900a961c4b8 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 3 Dec 2014 16:07:13 +0200 Subject: Bluetooth: Fix minor coding style issue in smp.c The convention for checking for NULL pointers is !ptr and not ptr == NULL. This patch fixes such an occurrence in smp.c. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index a7b973b..7435940 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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; } -- cgit v1.1 From 580039e838a7efaee0048b0857d1bb5582327aa5 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 3 Dec 2014 16:26:37 +0200 Subject: Bluetooth: Fix false-positive "uninitialized" compiler warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 7435940..96bf16d 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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: -- cgit v1.1 From c0371da6047abd261bc483c744dbc7d81a116172 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 24 Nov 2014 10:42:55 -0500 Subject: put iov_iter into msghdr Note that the code _using_ ->msg_iter at that point will be very unhappy with anything other than unshifted iovec-backed iov_iter. We still need to convert users to proper primitives. Signed-off-by: Al Viro --- net/bluetooth/smp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 069b76e..21f555b 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -268,8 +268,7 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data) memset(&msg, 0, sizeof(msg)); - msg.msg_iov = (struct iovec *) &iv; - msg.msg_iovlen = 2; + iov_iter_init(&msg.msg_iter, WRITE, (struct iovec *)iv, 2, 1 + len); l2cap_chan_send(chan, &msg, 1 + len); -- cgit v1.1 From 17836394e578b8d6475ecdb309ad1356bbcf37a2 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 24 Nov 2014 17:07:38 -0500 Subject: first fruits - kill l2cap ->memcpy_fromiovec() Just use copy_from_iter(). That's what this method is trying to do in all cases, in a very convoluted fashion. Signed-off-by: Al Viro --- net/bluetooth/smp.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 21f555b..de7dc75 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -268,7 +268,7 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data) memset(&msg, 0, sizeof(msg)); - iov_iter_init(&msg.msg_iter, WRITE, (struct iovec *)iv, 2, 1 + len); + iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, iv, 2, 1 + len); l2cap_chan_send(chan, &msg, 1 + len); @@ -1629,7 +1629,6 @@ static const struct l2cap_ops smp_chan_ops = { .suspend = l2cap_chan_no_suspend, .set_shutdown = l2cap_chan_no_set_shutdown, .get_sndtimeo = l2cap_chan_no_get_sndtimeo, - .memcpy_fromiovec = l2cap_chan_no_memcpy_fromiovec, }; static inline struct l2cap_chan *smp_new_conn_cb(struct l2cap_chan *pchan) @@ -1678,7 +1677,6 @@ static const struct l2cap_ops smp_root_chan_ops = { .resume = l2cap_chan_no_resume, .set_shutdown = l2cap_chan_no_set_shutdown, .get_sndtimeo = l2cap_chan_no_get_sndtimeo, - .memcpy_fromiovec = l2cap_chan_no_memcpy_fromiovec, }; int smp_register(struct hci_dev *hdev) -- cgit v1.1