static int smp_encrypt_link(struct hci_conn *hcon, struct link_key *key) { struct key_master_id *master; u8 sec_level; u8 zerobuf[8]; if (!hcon || !key || !key->data) return -EINVAL; memset(zerobuf, 0, sizeof(zerobuf)); master = (void *) key->data; if (!master->ediv && !memcmp(master->rand, zerobuf, sizeof(zerobuf))) return -EINVAL; hcon->enc_key_size = key->pin_len; hcon->sec_req = TRUE; sec_level = authreq_to_seclevel(key->auth); BT_DBG("cur %d, req: %d", hcon->sec_level, sec_level); if (sec_level > hcon->sec_level) hcon->pending_sec_level = sec_level; if (!(hcon->link_mode & HCI_LM_ENCRYPT)) hci_conn_hold(hcon); hci_le_start_enc(hcon, master->ediv, master->rand, key->val); return 0; }
int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) { struct hci_conn *hcon = conn->hcon; __u8 authreq; BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level); if (IS_ERR(hcon->hdev->tfm)) return 1; if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) return -EINPROGRESS; if (sec_level == BT_SECURITY_LOW) return 1; if (hcon->sec_level > sec_level) return 1; authreq = seclevel_to_authreq(sec_level); if (hcon->link_mode & HCI_LM_MASTER) { struct link_key *key; key = hci_find_link_key_type(hcon->hdev, conn->dst, KEY_TYPE_LTK); if (key) { struct key_master_id *master = (void *) key->data; hci_le_start_enc(hcon, master->ediv, master->rand, key->val); hcon->enc_key_size = key->pin_len; goto done; } } if (hcon->link_mode & HCI_LM_MASTER) { struct smp_cmd_pairing cp; build_pairing_cmd(conn, &cp, NULL, authreq); conn->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&conn->preq[1], &cp, sizeof(cp)); mod_timer(&conn->security_timer, jiffies + msecs_to_jiffies(SMP_TIMEOUT)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); } else { struct smp_cmd_security_req cp; cp.auth_req = authreq; smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp); } done: hcon->pending_sec_level = sec_level; set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); return 0; }
int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) { struct hci_conn *hcon = conn->hcon; struct smp_chan *smp = conn->smp_chan; __u8 authreq; BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level); if (!lmp_host_le_capable(hcon->hdev)) return 1; if (sec_level == BT_SECURITY_LOW) return 1; if (hcon->sec_level >= sec_level) return 1; if (hcon->link_mode & HCI_LM_MASTER) if (smp_ltk_encrypt(conn)) goto done; if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) return 0; smp = smp_chan_create(conn); if (!smp) return 1; authreq = seclevel_to_authreq(sec_level); if (hcon->link_mode & HCI_LM_MASTER) { struct smp_cmd_pairing cp; struct link_key *key; key = hci_find_link_key_type(hcon->hdev, conn->dst, HCI_LK_SMP_LTK); if (key) { struct key_master_id *master = (void *) key->data; hci_le_start_enc(hcon, master->ediv, master->rand, key->val); goto done; } build_pairing_cmd(conn, &cp, NULL, authreq); smp->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&smp->preq[1], &cp, sizeof(cp)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); } else { struct smp_cmd_security_req cp; cp.auth_req = authreq; smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp); } done: hcon->pending_sec_level = sec_level; return 0; }
static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct hci_conn *hcon = conn->hcon; struct smp_cmd_security_req *rp = (void *) skb->data; struct smp_cmd_pairing cp; struct link_key *key; BT_DBG("conn %p", conn); if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) return 0; key = hci_find_link_key_type(hcon->hdev, conn->dst, KEY_TYPE_LTK); if (key && ((key->auth & SMP_AUTH_MITM) || !(rp->auth_req & SMP_AUTH_MITM))) { struct key_master_id *master = (void *) key->data; hci_le_start_enc(hcon, master->ediv, master->rand, key->val); hcon->enc_key_size = key->pin_len; hcon->sec_req = TRUE; hcon->sec_level = authreq_to_seclevel(rp->auth_req); return 0; } hcon->sec_req = FALSE; skb_pull(skb, sizeof(*rp)); memset(&cp, 0, sizeof(cp)); build_pairing_cmd(conn, &cp, NULL, rp->auth_req); hcon->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&hcon->preq[1], &cp, sizeof(cp)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); mod_timer(&hcon->smp_timer, jiffies + msecs_to_jiffies(SMP_TIMEOUT)); set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); return 0; }
static u8 smp_ltk_encrypt(struct l2cap_conn *conn) { struct smp_ltk *key; struct hci_conn *hcon = conn->hcon; key = hci_find_ltk_by_addr(hcon->hdev, conn->dst, hcon->dst_type); if (!key) return 0; if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) return 1; hci_le_start_enc(hcon, key->ediv, key->rand, key->val); hcon->enc_key_size = key->enc_size; return 1; }
static u8 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->out); if (!key) return 0; if (sec_level > BT_SECURITY_MEDIUM && !key->authenticated) return 0; if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) return 1; hci_le_start_enc(hcon, key->ediv, key->rand, key->val); hcon->enc_key_size = key->enc_size; return 1; }
static int smp_encrypt_link(struct hci_conn *hcon, struct link_key *key) { struct key_master_id *master; u8 zerobuf[8]; if (!hcon || !key || !key->data) return -EINVAL; memset(zerobuf, 0, sizeof(zerobuf)); master = (void *) key->data; if (!master->ediv && !memcmp(master->rand, zerobuf, sizeof(zerobuf))) return -EINVAL; hcon->enc_key_size = key->pin_len; hcon->sec_req = TRUE; hci_le_start_enc(hcon, master->ediv, master->rand, key->val); return 0; }
static u8 smp_ltk_encrypt(struct l2cap_conn *conn) { struct link_key *key; struct key_master_id *master; struct hci_conn *hcon = conn->hcon; key = hci_find_link_key_type(hcon->hdev, conn->dst, HCI_LK_SMP_LTK); if (!key) return 0; if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) return 1; master = (void *) key->data; hci_le_start_enc(hcon, master->ediv, master->rand, key->val); hcon->enc_key_size = key->pin_len; return 1; }
static void random_work(struct work_struct *work) { struct smp_chan *smp = container_of(work, struct smp_chan, random); struct l2cap_conn *conn = smp->conn; struct hci_conn *hcon = conn->hcon; struct crypto_blkcipher *tfm = smp->tfm; u8 reason, confirm[16], res[16], key[16]; int ret; if (IS_ERR_OR_NULL(tfm)) { reason = SMP_UNSPECIFIED; goto error; } BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); if (hcon->out) ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, 0, conn->src, hcon->dst_type, conn->dst, res); else ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, hcon->dst_type, conn->dst, 0, conn->src, res); if (ret) { reason = SMP_UNSPECIFIED; goto error; } swap128(res, confirm); if (memcmp(smp->pcnf, confirm, sizeof(smp->pcnf)) != 0) { BT_ERR("Pairing failed (confirmation values mismatch)"); reason = SMP_CONFIRM_FAILED; goto error; } if (hcon->out) { u8 stk[16], rand[8]; __le16 ediv; memset(rand, 0, sizeof(rand)); ediv = 0; smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, key); swap128(key, stk); memset(stk + smp->enc_key_size, 0, SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) { reason = SMP_UNSPECIFIED; goto error; } hci_le_start_enc(hcon, ediv, rand, stk); hcon->enc_key_size = smp->enc_key_size; } else { u8 stk[16], r[16], rand[8]; __le16 ediv; memset(rand, 0, sizeof(rand)); ediv = 0; swap128(smp->prnd, r); smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r); smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, key); swap128(key, stk); memset(stk + smp->enc_key_size, 0, SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); hci_add_ltk(hcon->hdev, conn->dst, hcon->dst_type, HCI_SMP_STK_SLAVE, 0, 0, stk, smp->enc_key_size, ediv, rand); } return; error: smp_failure(conn, reason, 1); }
static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) { struct hci_conn *hcon = conn->hcon; struct crypto_blkcipher *tfm = hcon->hdev->tfm; int ret; u8 key[16], res[16], random[16], confirm[16]; swap128(skb->data, random); skb_pull(skb, sizeof(random)); if (conn->hcon->out) ret = smp_c1(tfm, hcon->tk, random, hcon->preq, hcon->prsp, 0, conn->src, hcon->dst_type, conn->dst, res); else ret = smp_c1(tfm, hcon->tk, random, hcon->preq, hcon->prsp, hcon->dst_type, conn->dst, 0, conn->src, res); if (ret) return SMP_UNSPECIFIED; BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); swap128(res, confirm); if (memcmp(hcon->pcnf, confirm, sizeof(hcon->pcnf)) != 0) { BT_ERR("Pairing failed (confirmation values mismatch)"); return SMP_CONFIRM_FAILED; } if (conn->hcon->out) { u8 stk[16], rand[8]; __le16 ediv; memset(rand, 0, sizeof(rand)); ediv = 0; smp_s1(tfm, hcon->tk, random, hcon->prnd, key); swap128(key, stk); memset(stk + hcon->smp_key_size, 0, SMP_MAX_ENC_KEY_SIZE - hcon->smp_key_size); hci_le_start_enc(hcon, ediv, rand, stk); hcon->enc_key_size = hcon->smp_key_size; } else { u8 stk[16], r[16], rand[8]; __le16 ediv; memset(rand, 0, sizeof(rand)); ediv = 0; swap128(hcon->prnd, r); smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r); smp_s1(tfm, hcon->tk, hcon->prnd, random, key); swap128(key, stk); memset(stk + hcon->smp_key_size, 0, SMP_MAX_ENC_KEY_SIZE - hcon->smp_key_size); hci_add_ltk(conn->hcon->hdev, 0, conn->dst, hcon->dst_type, hcon->smp_key_size, hcon->auth, ediv, rand, stk); } return 0; }
static void random_work(struct work_struct *work) { struct smp_chan *smp = container_of(work, struct smp_chan, random); struct l2cap_conn *conn = smp->conn; struct hci_conn *hcon = conn->hcon; struct hci_dev *hdev = hcon->hdev; struct crypto_blkcipher *tfm = hdev->tfm_aes; u8 reason, confirm[16]; int ret; if (IS_ERR_OR_NULL(tfm)) { reason = SMP_UNSPECIFIED; goto error; } BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); /* Prevent mutual access to hdev->tfm_aes */ hci_dev_lock(hdev); ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, hcon->init_addr_type, &hcon->init_addr, hcon->resp_addr_type, &hcon->resp_addr, confirm); hci_dev_unlock(hdev); if (ret) { reason = SMP_UNSPECIFIED; goto error; } if (memcmp(smp->pcnf, confirm, sizeof(smp->pcnf)) != 0) { BT_ERR("Pairing failed (confirmation values mismatch)"); reason = SMP_CONFIRM_FAILED; goto error; } if (hcon->out) { u8 stk[16]; __le64 rand = 0; __le16 ediv = 0; smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, stk); memset(stk + smp->enc_key_size, 0, SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) { reason = SMP_UNSPECIFIED; goto error; } hci_le_start_enc(hcon, ediv, rand, stk); hcon->enc_key_size = smp->enc_key_size; } else { u8 stk[16], auth; __le64 rand = 0; __le16 ediv = 0; smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd), smp->prnd); smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, stk); memset(stk + smp->enc_key_size, 0, SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); if (hcon->pending_sec_level == BT_SECURITY_HIGH) auth = 1; else auth = 0; hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type, HCI_SMP_STK_SLAVE, auth, stk, smp->enc_key_size, ediv, rand); } return; error: smp_failure(conn, reason); }