static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_master_ident *rp = (void *) skb->data; struct smp_cmd_pairing *paircmd = (void *) &conn->prsp[1]; struct link_key *key; struct key_master_id *id; u8 keydist = paircmd->init_key_dist; skb_pull(skb, sizeof(*rp)); key = hci_find_link_key_type(conn->hcon->hdev, conn->dst, KEY_TYPE_LTK); if (key == NULL) return SMP_UNSPECIFIED; BT_DBG("keydist 0x%x", keydist); id = (void *) key->data; id->ediv = rp->ediv; memcpy(id->rand, rp->rand, sizeof(rp->rand)); hci_add_ltk(conn->hcon->hdev, 1, conn->src, conn->smp_key_size, rp->ediv, rp->rand, key->val); smp_distribute_keys(conn, 1); return 0; }
static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) { struct hci_conn *hcon = conn->hcon; struct smp_cmd_master_ident *rp = (void *) skb->data; struct smp_cmd_pairing *paircmd = (void *) &hcon->prsp[1]; struct link_key *key; u8 *keydist; skb_pull(skb, sizeof(*rp)); key = hci_find_link_key_type(hcon->hdev, conn->dst, KEY_TYPE_LTK); if (key == NULL) return SMP_UNSPECIFIED; if (hcon->out) keydist = &paircmd->resp_key_dist; else keydist = &paircmd->init_key_dist; BT_DBG("keydist 0x%x", *keydist); hci_add_ltk(hcon->hdev, 1, conn->dst, hcon->dst_type, hcon->smp_key_size, hcon->auth, rp->ediv, rp->rand, key->val); *keydist &= ~SMP_DIST_ENC_KEY; if (hcon->out) { if (!(*keydist)) smp_distribute_keys(conn, 1); } return 0; }
static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_master_ident *rp = (void *) skb->data; struct smp_chan *smp = conn->smp_chan; struct hci_dev *hdev = conn->hcon->hdev; struct hci_conn *hcon = conn->hcon; struct smp_ltk *ltk; u8 authenticated; BT_DBG("conn %p", conn); if (skb->len < sizeof(*rp)) return SMP_UNSPECIFIED; /* Ignore this PDU if it wasn't requested */ if (!(smp->remote_key_dist & SMP_DIST_ENC_KEY)) return 0; /* Mark the information as received */ smp->remote_key_dist &= ~SMP_DIST_ENC_KEY; 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, HCI_SMP_LTK, authenticated, smp->tk, smp->enc_key_size, rp->ediv, rp->rand); smp->ltk = ltk; if (!(smp->remote_key_dist & SMP_DIST_ID_KEY)) smp_distribute_keys(conn); hci_dev_unlock(hdev); return 0; }
static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_master_ident *rp = (void *) skb->data; skb_pull(skb, sizeof(*rp)); hci_add_ltk(conn->hcon->hdev, 1, conn->src, conn->smp_key_size, rp->ediv, rp->rand, conn->tk); smp_distribute_keys(conn, 1); return 0; }
static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_encrypt_info *rp = (void *) skb->data; u8 rand[8]; int err; skb_pull(skb, sizeof(*rp)); BT_DBG("conn %p", conn); memset(rand, 0, sizeof(rand)); err = hci_add_ltk(conn->hcon->hdev, 0, conn->dst, 0, 0, rand, rp->ltk); if (err) return SMP_UNSPECIFIED; return 0; }
static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_master_ident *rp = (void *) skb->data; struct smp_chan *smp = conn->smp_chan; struct hci_dev *hdev = conn->hcon->hdev; struct hci_conn *hcon = conn->hcon; u8 authenticated; skb_pull(skb, sizeof(*rp)); hci_dev_lock(hdev); authenticated = (conn->hcon->sec_level == BT_SECURITY_HIGH); hci_add_ltk(conn->hcon->hdev, conn->dst, hcon->dst_type, HCI_SMP_LTK, 1, authenticated, smp->tk, smp->enc_key_size, rp->ediv, rp->rand); smp_distribute_keys(conn, 1); hci_dev_unlock(hdev); return 0; }
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; }
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; }
int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) { struct smp_cmd_pairing *req, *rsp; __u8 *keydist; BT_DBG("conn %p force %d", conn, force); if (IS_ERR(conn->hcon->hdev->tfm)) return PTR_ERR(conn->hcon->hdev->tfm); rsp = (void *) &conn->prsp[1]; /* The responder sends its keys first */ if (!force && conn->hcon->out && (rsp->resp_key_dist & 0x07)) return 0; req = (void *) &conn->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; __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(conn->hcon->hdev, 1, conn->dst, conn->smp_key_size, 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; /* 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; } 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); }
int smp_distribute_keys(struct l2cap_conn *conn) { struct smp_cmd_pairing *req, *rsp; struct smp_chan *smp = conn->smp_chan; struct hci_conn *hcon = conn->hcon; struct hci_dev *hdev = hcon->hdev; __u8 *keydist; BT_DBG("conn %p", conn); if (!test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) return 0; rsp = (void *) &smp->prsp[1]; /* The responder sends its keys first */ if (hcon->out && (smp->remote_key_dist & 0x07)) return 0; req = (void *) &smp->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; struct smp_ltk *ltk; u8 authenticated; __le16 ediv; __le64 rand; get_random_bytes(enc.ltk, sizeof(enc.ltk)); get_random_bytes(&ediv, sizeof(ediv)); get_random_bytes(&rand, sizeof(rand)); smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc); authenticated = hcon->sec_level == BT_SECURITY_HIGH; ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, HCI_SMP_LTK_SLAVE, authenticated, enc.ltk, smp->enc_key_size, ediv, rand); smp->slave_ltk = ltk; ident.ediv = ediv; ident.rand = rand; 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; memcpy(idinfo.irk, hdev->irk, sizeof(idinfo.irk)); smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo); /* The hci_conn contains the local identity address * after the connection has been established. * * This is true even when the connection has been * established using a resolvable random address. */ bacpy(&addrinfo.bdaddr, &hcon->src); addrinfo.addr_type = hcon->src_type; 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; struct smp_csrk *csrk; /* Generate a new random key */ get_random_bytes(sign.csrk, sizeof(sign.csrk)); csrk = kzalloc(sizeof(*csrk), GFP_KERNEL); if (csrk) { csrk->master = 0x00; memcpy(csrk->val, sign.csrk, sizeof(csrk->val)); } smp->slave_csrk = csrk; smp_send_cmd(conn, SMP_CMD_SIGN_INFO, sizeof(sign), &sign); *keydist &= ~SMP_DIST_SIGN; } /* If there are still keys to be received wait for them */ if ((smp->remote_key_dist & 0x07)) return 0; clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags); cancel_delayed_work_sync(&conn->security_timer); set_bit(SMP_FLAG_COMPLETE, &smp->smp_flags); smp_notify_keys(conn); smp_chan_destroy(conn); return 0; }