diff options
author | Johan Hedberg <johan.hedberg@intel.com> | 2016-12-08 07:32:54 +0100 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2016-12-08 07:50:24 +0100 |
commit | a62da6f14db79bd7ea435ab095e998b31b3dbb22 (patch) | |
tree | c7266f8bc79ebab0e6ee709a43de792116b83b24 /net/bluetooth/smp.c | |
parent | Bluetooth: btmrvl: drop duplicate header slab.h (diff) | |
download | linux-a62da6f14db79bd7ea435ab095e998b31b3dbb22.tar.xz linux-a62da6f14db79bd7ea435ab095e998b31b3dbb22.zip |
Bluetooth: SMP: Add support for H7 crypto function and CT2 auth flag
Bluetooth 5.0 introduces a new H7 key generation function that's used
when both sides of the pairing set the CT2 authentication flag to 1.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/smp.c')
-rw-r--r-- | net/bluetooth/smp.c | 85 |
1 files changed, 68 insertions, 17 deletions
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 43faf2aea2ab..fae391f1871f 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -57,7 +57,7 @@ #define SMP_TIMEOUT msecs_to_jiffies(30000) #define AUTH_REQ_MASK(dev) (hci_dev_test_flag(dev, HCI_SC_ENABLED) ? \ - 0x1f : 0x07) + 0x3f : 0x07) #define KEY_DIST_MASK 0x07 /* Maximum message length that can be passed to aes_cmac */ @@ -76,6 +76,7 @@ enum { SMP_FLAG_DHKEY_PENDING, SMP_FLAG_REMOTE_OOB, SMP_FLAG_LOCAL_OOB, + SMP_FLAG_CT2, }; struct smp_dev { @@ -357,6 +358,22 @@ static int smp_h6(struct crypto_shash *tfm_cmac, const u8 w[16], return err; } +static int smp_h7(struct crypto_shash *tfm_cmac, const u8 w[16], + const u8 salt[16], u8 res[16]) +{ + int err; + + SMP_DBG("w %16phN salt %16phN", w, salt); + + err = aes_cmac(tfm_cmac, salt, w, 16, 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. */ @@ -1130,20 +1147,31 @@ static void sc_add_ltk(struct smp_chan *smp) 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 }; + /* From core spec. Spells out in ASCII as 'lebr'. */ 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)) { - kzfree(smp->link_key); - smp->link_key = NULL; - return; + if (test_bit(SMP_FLAG_CT2, &smp->flags)) { + /* SALT = 0x00000000000000000000000000000000746D7031 */ + const u8 salt[16] = { 0x31, 0x70, 0x6d, 0x74 }; + + if (smp_h7(smp->tfm_cmac, smp->tk, salt, smp->link_key)) { + kzfree(smp->link_key); + smp->link_key = NULL; + return; + } + } else { + /* From core spec. Spells out in ASCII as 'tmp1'. */ + const u8 tmp1[4] = { 0x31, 0x70, 0x6d, 0x74 }; + + if (smp_h6(smp->tfm_cmac, smp->tk, tmp1, smp->link_key)) { + kzfree(smp->link_key); + smp->link_key = NULL; + return; + } } if (smp_h6(smp->tfm_cmac, smp->link_key, lebr, smp->link_key)) { @@ -1169,10 +1197,7 @@ static void smp_allow_key_dist(struct smp_chan *smp) 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 }; + /* From core spec. Spells out in ASCII as 'brle'. */ const u8 brle[4] = { 0x65, 0x6c, 0x72, 0x62 }; struct hci_conn *hcon = smp->conn->hcon; struct hci_dev *hdev = hcon->hdev; @@ -1187,8 +1212,19 @@ static void sc_generate_ltk(struct smp_chan *smp) 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 (test_bit(SMP_FLAG_CT2, &smp->flags)) { + /* SALT = 0x00000000000000000000000000000000746D7032 */ + const u8 salt[16] = { 0x32, 0x70, 0x6d, 0x74 }; + + if (smp_h7(smp->tfm_cmac, key->val, salt, smp->tk)) + return; + } else { + /* From core spec. Spells out in ASCII as 'tmp2'. */ + const u8 tmp2[4] = { 0x32, 0x70, 0x6d, 0x74 }; + + if (smp_h6(smp->tfm_cmac, key->val, tmp2, smp->tk)) + return; + } if (smp_h6(smp->tfm_cmac, smp->tk, brle, smp->tk)) return; @@ -1669,6 +1705,7 @@ static void build_bredr_pairing_cmd(struct smp_chan *smp, if (!rsp) { memset(req, 0, sizeof(*req)); + req->auth_req = SMP_AUTH_CT2; req->init_key_dist = local_dist; req->resp_key_dist = remote_dist; req->max_key_size = conn->hcon->enc_key_size; @@ -1680,6 +1717,7 @@ static void build_bredr_pairing_cmd(struct smp_chan *smp, memset(rsp, 0, sizeof(*rsp)); + rsp->auth_req = SMP_AUTH_CT2; rsp->max_key_size = conn->hcon->enc_key_size; rsp->init_key_dist = req->init_key_dist & remote_dist; rsp->resp_key_dist = req->resp_key_dist & local_dist; @@ -1744,6 +1782,9 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) build_bredr_pairing_cmd(smp, req, &rsp); + if (req->auth_req & SMP_AUTH_CT2) + set_bit(SMP_FLAG_CT2, &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; @@ -1761,9 +1802,13 @@ 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) + if (rsp.auth_req & SMP_AUTH_SC) { set_bit(SMP_FLAG_SC, &smp->flags); + if (rsp.auth_req & SMP_AUTH_CT2) + set_bit(SMP_FLAG_CT2, &smp->flags); + } + if (conn->hcon->io_capability == HCI_IO_NO_INPUT_OUTPUT) sec_level = BT_SECURITY_MEDIUM; else @@ -1917,6 +1962,9 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) */ smp->remote_key_dist &= rsp->resp_key_dist; + if ((req->auth_req & SMP_AUTH_CT2) && (auth & SMP_AUTH_CT2)) + set_bit(SMP_FLAG_CT2, &smp->flags); + /* 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 */ @@ -2312,8 +2360,11 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) authreq = seclevel_to_authreq(sec_level); - if (hci_dev_test_flag(hcon->hdev, HCI_SC_ENABLED)) + if (hci_dev_test_flag(hcon->hdev, HCI_SC_ENABLED)) { authreq |= SMP_AUTH_SC; + if (hci_dev_test_flag(hcon->hdev, HCI_SSP_ENABLED)) + authreq |= SMP_AUTH_CT2; + } /* Require MITM if IO Capability allows or the security level * requires it. |