Commit 943a732a authored by Johan Hedberg's avatar Johan Hedberg Committed by Marcel Holtmann

Bluetooth: Fix smp_e byte order to be consistent with SMP specification

The SMP specification is written with the assumption that both key
information, plaintextData and encryptedData follow the same little
endian byte ordering as the rest of SMP.

Since the kernel crypto routines expect big endian data the code has had
to do various byte swapping tricks to make the behavior as expected,
however the swapping has been scattered all around the place.

This patch centralizes the byte order swapping into the smp_e function
by making its public interface match what the other SMP functions expect
as per specification. The benefit is vastly simplified calls to smp_e.
Signed-off-by: default avatarJohan Hedberg <johan.hedberg@intel.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 66bed1a2
...@@ -53,6 +53,7 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r) ...@@ -53,6 +53,7 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
{ {
struct blkcipher_desc desc; struct blkcipher_desc desc;
struct scatterlist sg; struct scatterlist sg;
uint8_t tmp[16], data[16];
int err; int err;
if (tfm == NULL) { if (tfm == NULL) {
...@@ -63,34 +64,40 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r) ...@@ -63,34 +64,40 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
desc.tfm = tfm; desc.tfm = tfm;
desc.flags = 0; desc.flags = 0;
err = crypto_blkcipher_setkey(tfm, k, 16); /* The most significant octet of key corresponds to k[0] */
swap128(k, tmp);
err = crypto_blkcipher_setkey(tfm, tmp, 16);
if (err) { if (err) {
BT_ERR("cipher setkey failed: %d", err); BT_ERR("cipher setkey failed: %d", err);
return err; return err;
} }
sg_init_one(&sg, r, 16); /* Most significant octet of plaintextData corresponds to data[0] */
swap128(r, data);
sg_init_one(&sg, data, 16);
err = crypto_blkcipher_encrypt(&desc, &sg, &sg, 16); err = crypto_blkcipher_encrypt(&desc, &sg, &sg, 16);
if (err) if (err)
BT_ERR("Encrypt data error %d", err); BT_ERR("Encrypt data error %d", err);
/* Most significant octet of encryptedData corresponds to data[0] */
swap128(data, r);
return err; 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, u8 irk[16], u8 r[3], u8 res[3])
{ {
u8 _res[16], k[16]; u8 _res[16];
int err; int err;
/* r' = padding || r */ /* r' = padding || r */
memset(_res, 0, 13); memcpy(_res, r, 3);
_res[13] = r[2]; memset(_res + 3, 0, 13);
_res[14] = r[1];
_res[15] = r[0];
swap128(irk, k); err = smp_e(tfm, irk, _res);
err = smp_e(tfm, k, _res);
if (err) { if (err) {
BT_ERR("Encrypt error"); BT_ERR("Encrypt error");
return err; return err;
...@@ -102,9 +109,7 @@ static int smp_ah(struct crypto_blkcipher *tfm, u8 irk[16], u8 r[3], u8 res[3]) ...@@ -102,9 +109,7 @@ static int smp_ah(struct crypto_blkcipher *tfm, u8 irk[16], u8 r[3], u8 res[3])
* by taking the least significant 24 bits of the output of e as the * by taking the least significant 24 bits of the output of e as the
* result of ah. * result of ah.
*/ */
res[0] = _res[15]; memcpy(res, _res, 3);
res[1] = _res[14];
res[2] = _res[13];
return 0; return 0;
} }
...@@ -152,16 +157,15 @@ static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16], ...@@ -152,16 +157,15 @@ static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16],
memset(p1, 0, 16); memset(p1, 0, 16);
/* p1 = pres || preq || _rat || _iat */ /* p1 = pres || preq || _rat || _iat */
swap56(pres, p1); p1[0] = _iat;
swap56(preq, p1 + 7); p1[1] = _rat;
p1[14] = _rat; memcpy(p1 + 2, preq, 7);
p1[15] = _iat; memcpy(p1 + 9, pres, 7);
memset(p2, 0, 16);
/* p2 = padding || ia || ra */ /* p2 = padding || ia || ra */
baswap((bdaddr_t *) (p2 + 4), ia); memcpy(p2, ra, 6);
baswap((bdaddr_t *) (p2 + 10), ra); memcpy(p2 + 6, ia, 6);
memset(p2 + 12, 0, 4);
/* res = r XOR p1 */ /* res = r XOR p1 */
u128_xor((u128 *) res, (u128 *) r, (u128 *) p1); u128_xor((u128 *) res, (u128 *) r, (u128 *) p1);
...@@ -190,8 +194,8 @@ static int smp_s1(struct crypto_blkcipher *tfm, u8 k[16], u8 r1[16], ...@@ -190,8 +194,8 @@ static int smp_s1(struct crypto_blkcipher *tfm, u8 k[16], u8 r1[16],
int err; int err;
/* Just least significant octets from r1 and r2 are considered */ /* Just least significant octets from r1 and r2 are considered */
memcpy(_r, r1 + 8, 8); memcpy(_r, r2, 8);
memcpy(_r + 8, r2 + 8, 8); memcpy(_r + 8, r1, 8);
err = smp_e(tfm, k, _r); err = smp_e(tfm, k, _r);
if (err) if (err)
...@@ -405,13 +409,10 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, ...@@ -405,13 +409,10 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
/* Generate random passkey. Not valid until confirmed. */ /* Generate random passkey. Not valid until confirmed. */
if (method == CFM_PASSKEY) { if (method == CFM_PASSKEY) {
u8 key[16]; memset(smp->tk, 0, sizeof(smp->tk));
memset(key, 0, sizeof(key));
get_random_bytes(&passkey, sizeof(passkey)); get_random_bytes(&passkey, sizeof(passkey));
passkey %= 1000000; passkey %= 1000000;
put_unaligned_le32(passkey, key); put_unaligned_le32(passkey, smp->tk);
swap128(key, smp->tk);
BT_DBG("PassKey: %d", passkey); BT_DBG("PassKey: %d", passkey);
} }
...@@ -438,7 +439,7 @@ static void confirm_work(struct work_struct *work) ...@@ -438,7 +439,7 @@ static void confirm_work(struct work_struct *work)
struct crypto_blkcipher *tfm = hdev->tfm_aes; struct crypto_blkcipher *tfm = hdev->tfm_aes;
struct smp_cmd_pairing_confirm cp; struct smp_cmd_pairing_confirm cp;
int ret; int ret;
u8 res[16], reason; u8 reason;
BT_DBG("conn %p", conn); BT_DBG("conn %p", conn);
...@@ -447,7 +448,8 @@ static void confirm_work(struct work_struct *work) ...@@ -447,7 +448,8 @@ static void confirm_work(struct work_struct *work)
ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
conn->hcon->init_addr_type, &conn->hcon->init_addr, conn->hcon->init_addr_type, &conn->hcon->init_addr,
conn->hcon->resp_addr_type, &conn->hcon->resp_addr, res); conn->hcon->resp_addr_type, &conn->hcon->resp_addr,
cp.confirm_val);
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
...@@ -458,7 +460,6 @@ static void confirm_work(struct work_struct *work) ...@@ -458,7 +460,6 @@ static void confirm_work(struct work_struct *work)
clear_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags); clear_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags);
swap128(res, cp.confirm_val);
smp_send_cmd(smp->conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); smp_send_cmd(smp->conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
return; return;
...@@ -474,7 +475,7 @@ static void random_work(struct work_struct *work) ...@@ -474,7 +475,7 @@ static void random_work(struct work_struct *work)
struct hci_conn *hcon = conn->hcon; struct hci_conn *hcon = conn->hcon;
struct hci_dev *hdev = hcon->hdev; struct hci_dev *hdev = hcon->hdev;
struct crypto_blkcipher *tfm = hdev->tfm_aes; struct crypto_blkcipher *tfm = hdev->tfm_aes;
u8 reason, confirm[16], res[16], key[16]; u8 reason, confirm[16];
int ret; int ret;
if (IS_ERR_OR_NULL(tfm)) { if (IS_ERR_OR_NULL(tfm)) {
...@@ -489,7 +490,7 @@ static void random_work(struct work_struct *work) ...@@ -489,7 +490,7 @@ static void random_work(struct work_struct *work)
ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
hcon->init_addr_type, &hcon->init_addr, hcon->init_addr_type, &hcon->init_addr,
hcon->resp_addr_type, &hcon->resp_addr, res); hcon->resp_addr_type, &hcon->resp_addr, confirm);
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
...@@ -498,8 +499,6 @@ static void random_work(struct work_struct *work) ...@@ -498,8 +499,6 @@ static void random_work(struct work_struct *work)
goto error; goto error;
} }
swap128(res, confirm);
if (memcmp(smp->pcnf, confirm, sizeof(smp->pcnf)) != 0) { if (memcmp(smp->pcnf, confirm, sizeof(smp->pcnf)) != 0) {
BT_ERR("Pairing failed (confirmation values mismatch)"); BT_ERR("Pairing failed (confirmation values mismatch)");
reason = SMP_CONFIRM_FAILED; reason = SMP_CONFIRM_FAILED;
...@@ -511,8 +510,7 @@ static void random_work(struct work_struct *work) ...@@ -511,8 +510,7 @@ static void random_work(struct work_struct *work)
__le64 rand = 0; __le64 rand = 0;
__le16 ediv = 0; __le16 ediv = 0;
smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, key); smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, stk);
swap128(key, stk);
memset(stk + smp->enc_key_size, 0, memset(stk + smp->enc_key_size, 0,
SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
...@@ -525,15 +523,14 @@ static void random_work(struct work_struct *work) ...@@ -525,15 +523,14 @@ static void random_work(struct work_struct *work)
hci_le_start_enc(hcon, ediv, rand, stk); hci_le_start_enc(hcon, ediv, rand, stk);
hcon->enc_key_size = smp->enc_key_size; hcon->enc_key_size = smp->enc_key_size;
} else { } else {
u8 stk[16], r[16]; u8 stk[16];
__le64 rand = 0; __le64 rand = 0;
__le16 ediv = 0; __le16 ediv = 0;
swap128(smp->prnd, r); smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd),
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r); smp->prnd);
smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, key); smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, stk);
swap128(key, stk);
memset(stk + smp->enc_key_size, 0, memset(stk + smp->enc_key_size, 0,
SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
...@@ -628,7 +625,6 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey) ...@@ -628,7 +625,6 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
struct l2cap_conn *conn = hcon->smp_conn; struct l2cap_conn *conn = hcon->smp_conn;
struct smp_chan *smp; struct smp_chan *smp;
u32 value; u32 value;
u8 key[16];
BT_DBG(""); BT_DBG("");
...@@ -640,10 +636,9 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey) ...@@ -640,10 +636,9 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
switch (mgmt_op) { switch (mgmt_op) {
case MGMT_OP_USER_PASSKEY_REPLY: case MGMT_OP_USER_PASSKEY_REPLY:
value = le32_to_cpu(passkey); value = le32_to_cpu(passkey);
memset(key, 0, sizeof(key)); memset(smp->tk, 0, sizeof(smp->tk));
BT_DBG("PassKey: %d", value); BT_DBG("PassKey: %d", value);
put_unaligned_le32(value, key); put_unaligned_le32(value, smp->tk);
swap128(key, smp->tk);
/* Fall Through */ /* Fall Through */
case MGMT_OP_USER_CONFIRM_REPLY: case MGMT_OP_USER_CONFIRM_REPLY:
set_bit(SMP_FLAG_TK_VALID, &smp->smp_flags); set_bit(SMP_FLAG_TK_VALID, &smp->smp_flags);
...@@ -787,17 +782,13 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -787,17 +782,13 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf)); memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf));
skb_pull(skb, sizeof(smp->pcnf)); skb_pull(skb, sizeof(smp->pcnf));
if (conn->hcon->out) { if (conn->hcon->out)
u8 random[16]; smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd),
smp->prnd);
swap128(smp->prnd, random); else if (test_bit(SMP_FLAG_TK_VALID, &smp->smp_flags))
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(random),
random);
} else if (test_bit(SMP_FLAG_TK_VALID, &smp->smp_flags)) {
queue_work(hdev->workqueue, &smp->confirm); queue_work(hdev->workqueue, &smp->confirm);
} else { else
set_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags); set_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags);
}
return 0; return 0;
} }
...@@ -812,7 +803,7 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -812,7 +803,7 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
if (skb->len < sizeof(smp->rrnd)) if (skb->len < sizeof(smp->rrnd))
return SMP_UNSPECIFIED; return SMP_UNSPECIFIED;
swap128(skb->data, smp->rrnd); memcpy(smp->rrnd, skb->data, sizeof(smp->rrnd));
skb_pull(skb, sizeof(smp->rrnd)); skb_pull(skb, sizeof(smp->rrnd));
queue_work(hdev->workqueue, &smp->random); queue_work(hdev->workqueue, &smp->random);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment