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; 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 smp_cmd_security_req *rp = (void *) skb->data; struct smp_cmd_pairing cp; struct hci_conn *hcon = conn->hcon; BT_DBG("conn %p", conn); if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) return 0; skb_pull(skb, sizeof(*rp)); memset(&cp, 0, sizeof(cp)); build_pairing_cmd(conn, &cp, NULL, rp->auth_req); conn->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&conn->preq[1], &cp, sizeof(cp)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); mod_timer(&conn->security_timer, jiffies + msecs_to_jiffies(SMP_TIMEOUT)); set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); return 0; }
static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb) { struct hci_conn *hcon = conn->hcon; int ret; BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); memcpy(hcon->pcnf, skb->data, sizeof(hcon->pcnf)); skb_pull(skb, sizeof(hcon->pcnf)); if (conn->hcon->out) { u8 random[16]; swap128(hcon->prnd, random); smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(random), random); } else if (hcon->tk_valid) { ret = send_pairing_confirm(conn); if (ret) return SMP_CONFIRM_FAILED; } else hcon->cfm_pending = TRUE; mod_timer(&hcon->smp_timer, jiffies + msecs_to_jiffies(SMP_TIMEOUT)); return 0; }
static int send_pairing_confirm(struct l2cap_conn *conn) { struct hci_conn *hcon = conn->hcon; struct crypto_blkcipher *tfm = hcon->hdev->tfm; struct smp_cmd_pairing_confirm cp; int ret; u8 res[16]; if (conn->hcon->out) ret = smp_c1(tfm, hcon->tk, hcon->prnd, hcon->preq, hcon->prsp, 0, conn->src, hcon->dst_type, conn->dst, res); else ret = smp_c1(tfm, hcon->tk, hcon->prnd, hcon->preq, hcon->prsp, hcon->dst_type, conn->dst, 0, conn->src, res); if (ret) return SMP_CONFIRM_FAILED; swap128(res, cp.confirm_val); hcon->cfm_pending = FALSE; smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); return 0; }
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 smp_chan *smp; BT_DBG("conn %p", conn); hcon->pending_sec_level = BT_SECURITY_MEDIUM; if (smp_ltk_encrypt(conn)) return 0; if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) return 0; smp = smp_chan_create(conn); skb_pull(skb, sizeof(*rp)); memset(&cp, 0, sizeof(cp)); build_pairing_cmd(conn, &cp, NULL, rp->auth_req); 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); return 0; }
static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_pairing rsp, *req = (void *) skb->data; u8 key_size; BT_DBG("conn %p", conn); conn->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&conn->preq[1], req, sizeof(*req)); skb_pull(skb, sizeof(*req)); if (req->oob_flag) return SMP_OOB_NOT_AVAIL; /* We didn't start the pairing, so no requirements */ build_pairing_cmd(conn, req, &rsp, SMP_AUTH_NONE); key_size = min(req->max_key_size, rsp.max_key_size); if (check_enc_key_size(conn, key_size)) return SMP_ENC_KEY_SIZE; /* Just works */ memset(conn->tk, 0, sizeof(conn->tk)); conn->prsp[0] = SMP_CMD_PAIRING_RSP; memcpy(&conn->prsp[1], &rsp, sizeof(rsp)); smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp); mod_timer(&conn->security_timer, jiffies + msecs_to_jiffies(SMP_TIMEOUT)); return 0; }
static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_pairing rsp, *req = (void *) skb->data; struct smp_chan *smp; u8 key_size; u8 auth = SMP_AUTH_NONE; int ret; BT_DBG("conn %p", conn); if (skb->len < sizeof(*req)) return SMP_UNSPECIFIED; if (conn->hcon->link_mode & HCI_LM_MASTER) return SMP_CMD_NOTSUPP; if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) smp = smp_chan_create(conn); else smp = conn->smp_chan; if (!smp) return SMP_UNSPECIFIED; smp->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&smp->preq[1], req, sizeof(*req)); skb_pull(skb, sizeof(*req)); /* We didn't start the pairing, so match remote */ if (req->auth_req & SMP_AUTH_BONDING) auth = req->auth_req; conn->hcon->pending_sec_level = authreq_to_seclevel(auth); build_pairing_cmd(conn, req, &rsp, auth); key_size = min(req->max_key_size, rsp.max_key_size); if (check_enc_key_size(conn, key_size)) return SMP_ENC_KEY_SIZE; get_random_bytes(smp->prnd, sizeof(smp->prnd)); 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); /* Request setup of TK */ ret = tk_request(conn, 0, auth, rsp.io_capability, req->io_capability); if (ret) return SMP_UNSPECIFIED; clear_bit(SMP_FLAG_INITIATOR, &smp->smp_flags); return 0; }
void smp_timeout(unsigned long arg) { struct l2cap_conn *conn = (void *) arg; u8 reason = SMP_UNSPECIFIED; BT_DBG("%p", conn); smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason); mgmt_auth_failed(conn->hcon->hdev->id, conn->dst, SMP_UNSPECIFIED); hci_conn_put(conn->hcon); }
static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send) { if (send) smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason); clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->pend); mgmt_auth_failed(conn->hcon->hdev, conn->dst, reason); del_timer(&conn->security_timer); smp_chan_destroy(conn); }
static void confirm_work(struct work_struct *work) { struct smp_chan *smp = container_of(work, struct smp_chan, confirm); struct l2cap_conn *conn = smp->conn; struct crypto_blkcipher *tfm; struct smp_cmd_pairing_confirm cp; int ret; u8 res[16], reason; BT_DBG("conn %p", conn); tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(tfm)) { reason = SMP_UNSPECIFIED; goto error; } smp->tfm = tfm; if (conn->hcon->out) ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, 0, conn->src, conn->hcon->dst_type, conn->dst, res); else ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, conn->hcon->dst_type, conn->dst, 0, conn->src, res); if (ret) { reason = SMP_UNSPECIFIED; goto error; } swap128(res, cp.confirm_val); smp_send_cmd(smp->conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); return; error: smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason); smp_chan_destroy(conn); }
static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb) { struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm; BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); memcpy(conn->pcnf, skb->data, sizeof(conn->pcnf)); skb_pull(skb, sizeof(conn->pcnf)); if (conn->hcon->out) { u8 random[16]; swap128(conn->prnd, random); smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(random), random); } else { struct smp_cmd_pairing_confirm cp; int ret; u8 res[16]; ret = smp_rand(conn->prnd); if (ret) return SMP_UNSPECIFIED; ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp, conn->hcon->dst_type, conn->dst, 0, conn->src, res); if (ret) return SMP_CONFIRM_FAILED; swap128(res, cp.confirm_val); smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); } mod_timer(&conn->security_timer, jiffies + msecs_to_jiffies(SMP_TIMEOUT)); 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))) { if (smp_encrypt_link(hcon, key) < 0) goto invalid_key; hcon->sec_level = authreq_to_seclevel(key->auth); if (!(hcon->link_mode & HCI_LM_ENCRYPT)) hci_conn_hold(hcon); return 0; } invalid_key: hcon->sec_req = FALSE; /* Switch to Pairing Connection Parameters */ hci_le_conn_update(hcon, SMP_MIN_CONN_INTERVAL, SMP_MAX_CONN_INTERVAL, SMP_MAX_CONN_LATENCY, SMP_SUPERVISION_TIMEOUT); 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); hci_conn_hold(hcon); return 0; }
void smp_timeout(unsigned long arg) { struct l2cap_conn *conn = (void *) arg; u8 reason = SMP_UNSPECIFIED; BT_DBG("%p", conn); smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason); clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->pend); mgmt_auth_failed(conn->hcon->hdev->id, conn->dst, SMP_UNSPECIFIED); hci_conn_put(conn->hcon); //delete the l2cap connection l2cap_conn_del(conn->hcon, EACCES, 0); }
void smp_timeout(unsigned long arg) { struct l2cap_conn *conn = (void *) arg; u8 reason = SMP_UNSPECIFIED; BT_DBG("%p", conn); smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason); clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->pend); #ifdef BLUETOOTH_CUSTOMIZE clear_bit(HCI_CONN_LE_CONN_UPDATE_PEND, &conn->hcon->pend); #endif /* BLUETOOTH_CUSTOMIZE */ mgmt_auth_failed(conn->hcon->hdev->id, conn->dst, SMP_UNSPECIFIED); hci_conn_put(conn->hcon); }
static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct hci_conn *hcon = conn->hcon; struct smp_cmd_pairing rsp, *req = (void *) skb->data; u8 key_size; u8 auth = SMP_AUTH_NONE; int ret; BT_DBG("conn %p", conn); hcon->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&hcon->preq[1], req, sizeof(*req)); skb_pull(skb, sizeof(*req)); if (req->oob_flag && hcon->oob) { auth = req->auth_req | SMP_AUTH_MITM; } else if (req->auth_req & SMP_AUTH_BONDING) { auth = SMP_AUTH_BONDING | SMP_AUTH_MITM; } build_pairing_cmd(conn, req, &rsp, auth); key_size = min(req->max_key_size, rsp.max_key_size); if (check_enc_key_size(conn, key_size)) return SMP_ENC_KEY_SIZE; ret = smp_rand(hcon->prnd); if (ret) return SMP_UNSPECIFIED; ret = tk_request(conn, req->oob_flag, auth, rsp.io_capability, req->io_capability); if (ret) return SMP_UNSPECIFIED; hcon->prsp[0] = SMP_CMD_PAIRING_RSP; memcpy(&hcon->prsp[1], &rsp, sizeof(rsp)); smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp); mod_timer(&hcon->smp_timer, jiffies + msecs_to_jiffies(SMP_TIMEOUT)); return 0; }
int le_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, void *cp) { struct mgmt_cp_user_passkey_reply *psk_reply = cp; struct l2cap_conn *conn = hcon->smp_conn; u8 key[16]; u8 reason = 0; int ret = 0; BT_DBG(""); hcon->tk_valid = TRUE; switch (mgmt_op) { case MGMT_OP_USER_CONFIRM_NEG_REPLY: reason = SMP_CONFIRM_FAILED; break; case MGMT_OP_USER_CONFIRM_REPLY: break; case MGMT_OP_USER_PASSKEY_REPLY: memset(key, 0, sizeof(key)); BT_DBG("PassKey: %d", psk_reply->passkey); put_unaligned_le32(psk_reply->passkey, key); swap128(key, hcon->tk); break; default: reason = SMP_CONFIRM_FAILED; ret = -EOPNOTSUPP; break; } if (reason) { BT_DBG("smp_send_cmd: SMP_CMD_PAIRING_FAIL"); smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason); del_timer(&hcon->smp_timer); clear_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); #ifdef BLUETOOTH_CUSTOMIZE clear_bit(HCI_CONN_LE_CONN_UPDATE_PEND, &hcon->pend); #endif /* BLUETOOTH_CUSTOMIZE */ mgmt_auth_failed(hcon->hdev->id, conn->dst, reason); hci_conn_put(hcon); } else if (hcon->cfm_pending) { BT_DBG("send_pairing_confirm"); ret = send_pairing_confirm(conn); } return ret; }
static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct hci_conn *hcon = conn->hcon; struct smp_cmd_pairing rsp, *req = (void *) skb->data; u8 key_size; u8 auth = SMP_AUTH_NONE; int ret; BT_DBG("conn %p", conn); hcon->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&hcon->preq[1], req, sizeof(*req)); skb_pull(skb, sizeof(*req)); if (req->oob_flag && hcon->oob) { /* By definition, OOB data pairing will have MITM protection */ auth = req->auth_req | SMP_AUTH_MITM; } else if (req->auth_req & SMP_AUTH_BONDING) { /* We will attempt MITM for all Bonding attempts */ auth = SMP_AUTH_BONDING | SMP_AUTH_MITM; } /* We didn't start the pairing, so no requirements */ build_pairing_cmd(conn, req, &rsp, auth); key_size = min(req->max_key_size, rsp.max_key_size); if (check_enc_key_size(conn, key_size)) return SMP_ENC_KEY_SIZE; ret = smp_rand(hcon->prnd); if (ret) return SMP_UNSPECIFIED; /* Request setup of TK */ ret = tk_request(conn, req->oob_flag, auth, rsp.io_capability, req->io_capability); if (ret) return SMP_UNSPECIFIED; hcon->prsp[0] = SMP_CMD_PAIRING_RSP; memcpy(&hcon->prsp[1], &rsp, sizeof(rsp)); smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp); mod_timer(&hcon->smp_timer, jiffies + msecs_to_jiffies(SMP_TIMEOUT)); return 0; }
static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send) { struct hci_conn *hcon = conn->hcon; if (send) smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason); clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->flags); mgmt_auth_failed(conn->hcon->hdev, conn->dst, hcon->type, hcon->dst_type, HCI_ERROR_AUTH_FAILURE); cancel_delayed_work_sync(&conn->security_timer); if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) smp_chan_destroy(conn); }
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 void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send) { struct hci_conn *hcon = conn->hcon; if (send) smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason); clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->flags); mgmt_auth_failed(conn->hcon->hdev, conn->dst, hcon->type, hcon->dst_type, reason); if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) { /* SSBT :: NEO (0213) */ /*del_timer(&conn->security_timer); */ del_timer_sync(&conn->security_timer); smp_chan_destroy(conn); } }
static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_pairing *req, *rsp = (void *) skb->data; struct smp_cmd_pairing_confirm cp; struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm; int ret; u8 res[16], key_size; BT_DBG("conn %p", conn); skb_pull(skb, sizeof(*rsp)); req = (void *) &conn->preq[1]; key_size = min(req->max_key_size, rsp->max_key_size); if (check_enc_key_size(conn, key_size)) return SMP_ENC_KEY_SIZE; if (rsp->oob_flag) return SMP_OOB_NOT_AVAIL; /* Just works */ memset(conn->tk, 0, sizeof(conn->tk)); conn->prsp[0] = SMP_CMD_PAIRING_RSP; memcpy(&conn->prsp[1], rsp, sizeof(*rsp)); ret = smp_rand(conn->prnd); if (ret) return SMP_UNSPECIFIED; ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp, 0, conn->src, conn->hcon->dst_type, conn->dst, res); if (ret) return SMP_UNSPECIFIED; swap128(res, cp.confirm_val); smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); return 0; }
static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_pairing rsp, *req = (void *) skb->data; struct smp_chan *smp; u8 key_size; int ret; BT_DBG("conn %p", conn); if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend)) smp = smp_chan_create(conn); smp = conn->smp_chan; smp->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&smp->preq[1], req, sizeof(*req)); skb_pull(skb, sizeof(*req)); if (req->oob_flag) return SMP_OOB_NOT_AVAIL; /* We didn't start the pairing, so no requirements */ build_pairing_cmd(conn, req, &rsp, SMP_AUTH_NONE); key_size = min(req->max_key_size, rsp.max_key_size); if (check_enc_key_size(conn, key_size)) return SMP_ENC_KEY_SIZE; /* Just works */ memset(smp->tk, 0, sizeof(smp->tk)); ret = smp_rand(smp->prnd); if (ret) return SMP_UNSPECIFIED; 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); return 0; }
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 smp_chan *smp; BT_DBG("conn %p", conn); if (skb->len < sizeof(*rp)) return SMP_UNSPECIFIED; if (!(conn->hcon->link_mode & HCI_LM_MASTER)) return SMP_CMD_NOTSUPP; hcon->pending_sec_level = authreq_to_seclevel(rp->auth_req); if (smp_ltk_encrypt(conn, hcon->pending_sec_level)) return 0; if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) return 0; smp = smp_chan_create(conn); skb_pull(skb, sizeof(*rp)); memset(&cp, 0, sizeof(cp)); build_pairing_cmd(conn, &cp, NULL, rp->auth_req); 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); clear_bit(SMP_FLAG_INITIATOR, &smp->smp_flags); return 0; }
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 smp_chan *smp; u8 sec_level; BT_DBG("conn %p", conn); sec_level = authreq_to_seclevel(rp->auth_req); if (smp_sufficient_security(hcon, sec_level)) return 0; if (sec_level > hcon->pending_sec_level) hcon->pending_sec_level = sec_level; if (smp_ltk_encrypt(conn, hcon->pending_sec_level)) return 0; if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) return 0; smp = smp_chan_create(conn); if (!smp) return SMP_UNSPECIFIED; skb_pull(skb, sizeof(*rp)); memset(&cp, 0, sizeof(cp)); build_pairing_cmd(conn, &cp, NULL, rp->auth_req); 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); return 0; }
static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_chan *smp = conn->smp_chan; struct hci_dev *hdev = conn->hcon->hdev; BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf)); skb_pull(skb, sizeof(smp->pcnf)); if (conn->hcon->out) { u8 random[16]; swap128(smp->prnd, random); smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(random), random); } else { queue_work(hdev->workqueue, &smp->confirm); } return 0; }
static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_chan *smp = conn->smp_chan; struct hci_dev *hdev = conn->hcon->hdev; BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); if (skb->len < sizeof(smp->pcnf)) return SMP_UNSPECIFIED; memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf)); skb_pull(skb, sizeof(smp->pcnf)); if (conn->hcon->out) smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd), smp->prnd); else if (test_bit(SMP_FLAG_TK_VALID, &smp->smp_flags)) queue_work(hdev->workqueue, &smp->confirm); else set_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags); return 0; }
static void confirm_work(struct work_struct *work) { struct smp_chan *smp = container_of(work, struct smp_chan, confirm); struct l2cap_conn *conn = smp->conn; struct hci_dev *hdev = conn->hcon->hdev; struct crypto_blkcipher *tfm = hdev->tfm_aes; struct smp_cmd_pairing_confirm cp; int ret; u8 reason; BT_DBG("conn %p", conn); /* Prevent mutual access to hdev->tfm_aes */ hci_dev_lock(hdev); ret = smp_c1(tfm, 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); hci_dev_unlock(hdev); if (ret) { reason = SMP_UNSPECIFIED; goto error; } clear_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags); smp_send_cmd(smp->conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); return; error: smp_failure(conn, reason); }
int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) { struct smp_cmd_pairing *req, *rsp; struct smp_chan *smp = conn->smp_chan; __u8 *keydist; BT_DBG("conn %p force %d", conn, force); if (!test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) return 0; rsp = (void *) &smp->prsp[1]; /* The responder sends its keys first */ if (!force && conn->hcon->out && (rsp->resp_key_dist & 0x07)) return 0; req = (void *) &smp->preq[1]; if (conn->hcon->out) { keydist = &rsp->init_key_dist; *keydist &= req->init_key_dist; } else { keydist = &rsp->resp_key_dist; *keydist &= req->resp_key_dist; } BT_DBG("keydist 0x%x", *keydist); if (*keydist & SMP_DIST_ENC_KEY) { struct smp_cmd_encrypt_info enc; struct smp_cmd_master_ident ident; struct hci_conn *hcon = conn->hcon; u8 authenticated; __le16 ediv; get_random_bytes(enc.ltk, sizeof(enc.ltk)); get_random_bytes(&ediv, sizeof(ediv)); get_random_bytes(ident.rand, sizeof(ident.rand)); smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc); authenticated = hcon->sec_level == BT_SECURITY_HIGH; hci_add_ltk(conn->hcon->hdev, conn->dst, hcon->dst_type, HCI_SMP_LTK_SLAVE, 1, authenticated, enc.ltk, smp->enc_key_size, ediv, ident.rand); ident.ediv = ediv; smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident); *keydist &= ~SMP_DIST_ENC_KEY; } if (*keydist & SMP_DIST_ID_KEY) { struct smp_cmd_ident_addr_info addrinfo; struct smp_cmd_ident_info idinfo; /* Send a dummy key */ get_random_bytes(idinfo.irk, sizeof(idinfo.irk)); smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo); /* Just public address */ memset(&addrinfo, 0, sizeof(addrinfo)); bacpy(&addrinfo.bdaddr, conn->src); smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo), &addrinfo); *keydist &= ~SMP_DIST_ID_KEY; } if (*keydist & SMP_DIST_SIGN) { struct smp_cmd_sign_info sign; /* Send a dummy key */ get_random_bytes(sign.csrk, sizeof(sign.csrk)); smp_send_cmd(conn, SMP_CMD_SIGN_INFO, sizeof(sign), &sign); *keydist &= ~SMP_DIST_SIGN; } if (conn->hcon->out || force) { clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags); cancel_delayed_work_sync(&conn->security_timer); smp_chan_destroy(conn); } 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 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 int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) { struct hci_conn *hcon = conn->hcon; struct smp_cmd_pairing *req, *rsp; __u8 *keydist; BT_DBG("conn %p force %d", conn, force); if (IS_ERR(hcon->hdev->tfm)) return PTR_ERR(hcon->hdev->tfm); rsp = (void *) &hcon->prsp[1]; if (!force && hcon->out && (rsp->resp_key_dist & 0x07)) return 0; req = (void *) &hcon->preq[1]; if (hcon->out) { keydist = &rsp->init_key_dist; *keydist &= req->init_key_dist; } else { keydist = &rsp->resp_key_dist; *keydist &= req->resp_key_dist; } BT_DBG("keydist 0x%x", *keydist); if (*keydist & SMP_DIST_ENC_KEY) { struct smp_cmd_encrypt_info enc; struct smp_cmd_master_ident ident; __le16 ediv; get_random_bytes(enc.ltk, sizeof(enc.ltk)); get_random_bytes(&ediv, sizeof(ediv)); get_random_bytes(ident.rand, sizeof(ident.rand)); smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc); hci_add_ltk(hcon->hdev, 1, conn->dst, hcon->dst_type, hcon->smp_key_size, hcon->auth, ediv, ident.rand, enc.ltk); ident.ediv = cpu_to_le16(ediv); smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident); *keydist &= ~SMP_DIST_ENC_KEY; } if (*keydist & SMP_DIST_ID_KEY) { struct smp_cmd_ident_addr_info addrinfo; struct smp_cmd_ident_info idinfo; get_random_bytes(idinfo.irk, sizeof(idinfo.irk)); smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo); memset(&addrinfo, 0, sizeof(addrinfo)); bacpy(&addrinfo.bdaddr, conn->src); smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo), &addrinfo); *keydist &= ~SMP_DIST_ID_KEY; } if (*keydist & SMP_DIST_SIGN) { struct smp_cmd_sign_info sign; get_random_bytes(sign.csrk, sizeof(sign.csrk)); smp_send_cmd(conn, SMP_CMD_SIGN_INFO, sizeof(sign), &sign); *keydist &= ~SMP_DIST_SIGN; } if (hcon->out) { if (hcon->disconn_cfm_cb) hcon->disconn_cfm_cb(hcon, 0); del_timer(&hcon->smp_timer); clear_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); hci_conn_put(hcon); } else if (rsp->resp_key_dist) { if (hcon->disconn_cfm_cb) hcon->disconn_cfm_cb(hcon, SMP_UNSPECIFIED); clear_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); mgmt_auth_failed(hcon->hdev->id, conn->dst, SMP_UNSPECIFIED); hci_conn_put(hcon); } return 0; }