blob: 0b96737d0ad36a27a7aaf8ed76dd9543ca0c2300 [file] [log] [blame]
Anderson Brigliaeb492e02011-06-09 18:50:40 -03001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23#include <net/bluetooth/bluetooth.h>
24#include <net/bluetooth/hci_core.h>
25#include <net/bluetooth/l2cap.h>
26#include <net/bluetooth/smp.h>
Anderson Brigliad22ef0b2011-06-09 18:50:44 -030027#include <linux/crypto.h>
Stephen Rothwellf70490e2011-06-23 12:58:55 +100028#include <linux/scatterlist.h>
Anderson Brigliad22ef0b2011-06-09 18:50:44 -030029#include <crypto/b128ops.h>
30
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -030031#define SMP_TIMEOUT 30000 /* 30 seconds */
32
Anderson Brigliad22ef0b2011-06-09 18:50:44 -030033static inline void swap128(u8 src[16], u8 dst[16])
34{
35 int i;
36 for (i = 0; i < 16; i++)
37 dst[15 - i] = src[i];
38}
39
40static inline void swap56(u8 src[7], u8 dst[7])
41{
42 int i;
43 for (i = 0; i < 7; i++)
44 dst[6 - i] = src[i];
45}
46
47static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
48{
49 struct blkcipher_desc desc;
50 struct scatterlist sg;
51 int err, iv_len;
52 unsigned char iv[128];
53
54 if (tfm == NULL) {
55 BT_ERR("tfm %p", tfm);
56 return -EINVAL;
57 }
58
59 desc.tfm = tfm;
60 desc.flags = 0;
61
62 err = crypto_blkcipher_setkey(tfm, k, 16);
63 if (err) {
64 BT_ERR("cipher setkey failed: %d", err);
65 return err;
66 }
67
68 sg_init_one(&sg, r, 16);
69
70 iv_len = crypto_blkcipher_ivsize(tfm);
71 if (iv_len) {
72 memset(&iv, 0xff, iv_len);
73 crypto_blkcipher_set_iv(tfm, iv, iv_len);
74 }
75
76 err = crypto_blkcipher_encrypt(&desc, &sg, &sg, 16);
77 if (err)
78 BT_ERR("Encrypt data error %d", err);
79
80 return err;
81}
82
83static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16],
84 u8 preq[7], u8 pres[7], u8 _iat, bdaddr_t *ia,
85 u8 _rat, bdaddr_t *ra, u8 res[16])
86{
87 u8 p1[16], p2[16];
88 int err;
89
90 memset(p1, 0, 16);
91
92 /* p1 = pres || preq || _rat || _iat */
93 swap56(pres, p1);
94 swap56(preq, p1 + 7);
95 p1[14] = _rat;
96 p1[15] = _iat;
97
98 memset(p2, 0, 16);
99
100 /* p2 = padding || ia || ra */
101 baswap((bdaddr_t *) (p2 + 4), ia);
102 baswap((bdaddr_t *) (p2 + 10), ra);
103
104 /* res = r XOR p1 */
105 u128_xor((u128 *) res, (u128 *) r, (u128 *) p1);
106
107 /* res = e(k, res) */
108 err = smp_e(tfm, k, res);
109 if (err) {
110 BT_ERR("Encrypt data error");
111 return err;
112 }
113
114 /* res = res XOR p2 */
115 u128_xor((u128 *) res, (u128 *) res, (u128 *) p2);
116
117 /* res = e(k, res) */
118 err = smp_e(tfm, k, res);
119 if (err)
120 BT_ERR("Encrypt data error");
121
122 return err;
123}
124
125static int smp_s1(struct crypto_blkcipher *tfm, u8 k[16],
126 u8 r1[16], u8 r2[16], u8 _r[16])
127{
128 int err;
129
130 /* Just least significant octets from r1 and r2 are considered */
131 memcpy(_r, r1 + 8, 8);
132 memcpy(_r + 8, r2 + 8, 8);
133
134 err = smp_e(tfm, k, _r);
135 if (err)
136 BT_ERR("Encrypt data error");
137
138 return err;
139}
140
141static int smp_rand(u8 *buf)
142{
143 get_random_bytes(buf, 16);
144
145 return 0;
146}
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300147
148static struct sk_buff *smp_build_cmd(struct l2cap_conn *conn, u8 code,
149 u16 dlen, void *data)
150{
151 struct sk_buff *skb;
152 struct l2cap_hdr *lh;
153 int len;
154
155 len = L2CAP_HDR_SIZE + sizeof(code) + dlen;
156
157 if (len > conn->mtu)
158 return NULL;
159
160 skb = bt_skb_alloc(len, GFP_ATOMIC);
161 if (!skb)
162 return NULL;
163
164 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
165 lh->len = cpu_to_le16(sizeof(code) + dlen);
166 lh->cid = cpu_to_le16(L2CAP_CID_SMP);
167
168 memcpy(skb_put(skb, sizeof(code)), &code, sizeof(code));
169
170 memcpy(skb_put(skb, dlen), data, dlen);
171
172 return skb;
173}
174
175static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
176{
177 struct sk_buff *skb = smp_build_cmd(conn, code, len, data);
178
179 BT_DBG("code 0x%2.2x", code);
180
181 if (!skb)
182 return;
183
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200184 skb->priority = HCI_PRIO_MAX;
185 hci_send_acl(conn->hchan, skb, 0);
Vinicius Costa Gomese2dcd112011-08-19 21:06:50 -0300186
187 mod_timer(&conn->security_timer, jiffies +
188 msecs_to_jiffies(SMP_TIMEOUT));
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300189}
190
Vinicius Costa Gomesb8e66ea2011-06-09 18:50:52 -0300191static void build_pairing_cmd(struct l2cap_conn *conn,
Vinicius Costa Gomes54790f72011-07-07 18:59:38 -0300192 struct smp_cmd_pairing *req,
193 struct smp_cmd_pairing *rsp,
194 __u8 authreq)
Vinicius Costa Gomesb8e66ea2011-06-09 18:50:52 -0300195{
Vinicius Costa Gomes54790f72011-07-07 18:59:38 -0300196 u8 dist_keys;
197
198 dist_keys = 0;
199 if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->flags)) {
Vinicius Costa Gomesca10b5e2011-08-25 20:02:37 -0300200 dist_keys = SMP_DIST_ENC_KEY;
Vinicius Costa Gomes54790f72011-07-07 18:59:38 -0300201 authreq |= SMP_AUTH_BONDING;
202 }
203
204 if (rsp == NULL) {
205 req->io_capability = conn->hcon->io_capability;
206 req->oob_flag = SMP_OOB_NOT_PRESENT;
207 req->max_key_size = SMP_MAX_ENC_KEY_SIZE;
208 req->init_key_dist = dist_keys;
209 req->resp_key_dist = dist_keys;
210 req->auth_req = authreq;
211 return;
212 }
213
214 rsp->io_capability = conn->hcon->io_capability;
215 rsp->oob_flag = SMP_OOB_NOT_PRESENT;
216 rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
217 rsp->init_key_dist = req->init_key_dist & dist_keys;
218 rsp->resp_key_dist = req->resp_key_dist & dist_keys;
219 rsp->auth_req = authreq;
Vinicius Costa Gomesb8e66ea2011-06-09 18:50:52 -0300220}
221
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300222static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
223{
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300224 struct smp_chan *smp = conn->smp_chan;
225
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300226 if ((max_key_size > SMP_MAX_ENC_KEY_SIZE) ||
227 (max_key_size < SMP_MIN_ENC_KEY_SIZE))
228 return SMP_ENC_KEY_SIZE;
229
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300230 smp->smp_key_size = max_key_size;
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300231
232 return 0;
233}
234
Brian Gix4f957a72011-11-23 08:28:36 -0800235static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send)
236{
237 if (send)
238 smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
239 &reason);
240
241 clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->pend);
242 mgmt_auth_failed(conn->hcon->hdev, conn->dst, reason);
243 del_timer(&conn->security_timer);
244 smp_chan_destroy(conn);
245}
246
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300247static void confirm_work(struct work_struct *work)
248{
249 struct smp_chan *smp = container_of(work, struct smp_chan, confirm);
250 struct l2cap_conn *conn = smp->conn;
251 struct crypto_blkcipher *tfm;
252 struct smp_cmd_pairing_confirm cp;
253 int ret;
254 u8 res[16], reason;
255
256 BT_DBG("conn %p", conn);
257
258 tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
259 if (IS_ERR(tfm)) {
260 reason = SMP_UNSPECIFIED;
261 goto error;
262 }
263
264 smp->tfm = tfm;
265
266 if (conn->hcon->out)
267 ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, 0,
268 conn->src, conn->hcon->dst_type, conn->dst,
269 res);
270 else
271 ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
272 conn->hcon->dst_type, conn->dst, 0, conn->src,
273 res);
274 if (ret) {
275 reason = SMP_UNSPECIFIED;
276 goto error;
277 }
278
279 swap128(res, cp.confirm_val);
280 smp_send_cmd(smp->conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
281
282 return;
283
284error:
Brian Gix4f957a72011-11-23 08:28:36 -0800285 smp_failure(conn, reason, 1);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300286}
287
288static void random_work(struct work_struct *work)
289{
290 struct smp_chan *smp = container_of(work, struct smp_chan, random);
291 struct l2cap_conn *conn = smp->conn;
292 struct hci_conn *hcon = conn->hcon;
293 struct crypto_blkcipher *tfm = smp->tfm;
294 u8 reason, confirm[16], res[16], key[16];
295 int ret;
296
297 if (IS_ERR_OR_NULL(tfm)) {
298 reason = SMP_UNSPECIFIED;
299 goto error;
300 }
301
302 BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
303
304 if (hcon->out)
305 ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, 0,
306 conn->src, hcon->dst_type, conn->dst,
307 res);
308 else
309 ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
310 hcon->dst_type, conn->dst, 0, conn->src,
311 res);
312 if (ret) {
313 reason = SMP_UNSPECIFIED;
314 goto error;
315 }
316
317 swap128(res, confirm);
318
319 if (memcmp(smp->pcnf, confirm, sizeof(smp->pcnf)) != 0) {
320 BT_ERR("Pairing failed (confirmation values mismatch)");
321 reason = SMP_CONFIRM_FAILED;
322 goto error;
323 }
324
325 if (hcon->out) {
326 u8 stk[16], rand[8];
327 __le16 ediv;
328
329 memset(rand, 0, sizeof(rand));
330 ediv = 0;
331
332 smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, key);
333 swap128(key, stk);
334
335 memset(stk + smp->smp_key_size, 0,
336 SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size);
337
338 if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) {
339 reason = SMP_UNSPECIFIED;
340 goto error;
341 }
342
343 hci_le_start_enc(hcon, ediv, rand, stk);
344 hcon->enc_key_size = smp->smp_key_size;
345 } else {
346 u8 stk[16], r[16], rand[8];
347 __le16 ediv;
348
349 memset(rand, 0, sizeof(rand));
350 ediv = 0;
351
352 swap128(smp->prnd, r);
353 smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r);
354
355 smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, key);
356 swap128(key, stk);
357
358 memset(stk + smp->smp_key_size, 0,
359 SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size);
360
361 hci_add_ltk(hcon->hdev, 0, conn->dst, smp->smp_key_size,
362 ediv, rand, stk);
363 }
364
365 return;
366
367error:
Brian Gix4f957a72011-11-23 08:28:36 -0800368 smp_failure(conn, reason, 1);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300369}
370
371static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
372{
373 struct smp_chan *smp;
374
375 smp = kzalloc(sizeof(struct smp_chan), GFP_ATOMIC);
376 if (!smp)
377 return NULL;
378
379 INIT_WORK(&smp->confirm, confirm_work);
380 INIT_WORK(&smp->random, random_work);
381
382 smp->conn = conn;
383 conn->smp_chan = smp;
384
385 hci_conn_hold(conn->hcon);
386
387 return smp;
388}
389
390void smp_chan_destroy(struct l2cap_conn *conn)
391{
Brian Gixc8eb9692011-11-23 08:28:35 -0800392 struct smp_chan *smp = conn->smp_chan;
393
394 clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend);
395
396 if (smp->tfm)
397 crypto_free_blkcipher(smp->tfm);
398
399 kfree(smp);
400 conn->smp_chan = NULL;
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300401 hci_conn_put(conn->hcon);
402}
403
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300404static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300405{
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300406 struct smp_cmd_pairing rsp, *req = (void *) skb->data;
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300407 struct smp_chan *smp;
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300408 u8 key_size;
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300409 int ret;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300410
411 BT_DBG("conn %p", conn);
412
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -0300413 if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend))
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300414 smp = smp_chan_create(conn);
415
416 smp = conn->smp_chan;
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -0300417
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300418 smp->preq[0] = SMP_CMD_PAIRING_REQ;
419 memcpy(&smp->preq[1], req, sizeof(*req));
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300420 skb_pull(skb, sizeof(*req));
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300421
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300422 if (req->oob_flag)
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300423 return SMP_OOB_NOT_AVAIL;
424
425 /* We didn't start the pairing, so no requirements */
Vinicius Costa Gomes54790f72011-07-07 18:59:38 -0300426 build_pairing_cmd(conn, req, &rsp, SMP_AUTH_NONE);
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300427
428 key_size = min(req->max_key_size, rsp.max_key_size);
429 if (check_enc_key_size(conn, key_size))
430 return SMP_ENC_KEY_SIZE;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300431
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300432 /* Just works */
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300433 memset(smp->tk, 0, sizeof(smp->tk));
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300434
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300435 ret = smp_rand(smp->prnd);
436 if (ret)
437 return SMP_UNSPECIFIED;
438
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300439 smp->prsp[0] = SMP_CMD_PAIRING_RSP;
440 memcpy(&smp->prsp[1], &rsp, sizeof(rsp));
Anderson Brigliaf01ead32011-06-09 18:50:45 -0300441
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300442 smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp);
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300443
444 return 0;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300445}
446
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300447static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300448{
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300449 struct smp_cmd_pairing *req, *rsp = (void *) skb->data;
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300450 struct smp_chan *smp = conn->smp_chan;
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300451 struct hci_dev *hdev = conn->hcon->hdev;
452 u8 key_size;
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300453 int ret;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300454
455 BT_DBG("conn %p", conn);
456
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300457 skb_pull(skb, sizeof(*rsp));
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300458
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300459 req = (void *) &smp->preq[1];
Vinicius Costa Gomes3158c502011-06-14 13:37:42 -0300460
461 key_size = min(req->max_key_size, rsp->max_key_size);
462 if (check_enc_key_size(conn, key_size))
463 return SMP_ENC_KEY_SIZE;
464
465 if (rsp->oob_flag)
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300466 return SMP_OOB_NOT_AVAIL;
467
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300468 /* Just works */
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300469 memset(smp->tk, 0, sizeof(smp->tk));
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300470
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300471 ret = smp_rand(smp->prnd);
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300472 if (ret)
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300473 return SMP_UNSPECIFIED;
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300474
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300475 smp->prsp[0] = SMP_CMD_PAIRING_RSP;
476 memcpy(&smp->prsp[1], rsp, sizeof(*rsp));
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300477
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300478 queue_work(hdev->workqueue, &smp->confirm);
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300479
480 return 0;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300481}
482
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300483static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300484{
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300485 struct smp_chan *smp = conn->smp_chan;
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300486 struct hci_dev *hdev = conn->hcon->hdev;
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300487
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300488 BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
489
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300490 memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf));
491 skb_pull(skb, sizeof(smp->pcnf));
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300492
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300493 if (conn->hcon->out) {
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300494 u8 random[16];
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300495
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300496 swap128(smp->prnd, random);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300497 smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(random),
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300498 random);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300499 } else {
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300500 queue_work(hdev->workqueue, &smp->confirm);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300501 }
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300502
503 return 0;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300504}
505
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300506static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300507{
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300508 struct smp_chan *smp = conn->smp_chan;
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300509 struct hci_dev *hdev = conn->hcon->hdev;
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300510
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300511 BT_DBG("conn %p", conn);
Anderson Briglia7d24ddc2011-06-09 18:50:46 -0300512
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300513 swap128(skb->data, smp->rrnd);
514 skb_pull(skb, sizeof(smp->rrnd));
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300515
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300516 queue_work(hdev->workqueue, &smp->random);
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300517
518 return 0;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300519}
520
Vinicius Costa Gomes988c5992011-08-25 20:02:28 -0300521static u8 smp_ltk_encrypt(struct l2cap_conn *conn)
522{
523 struct link_key *key;
524 struct key_master_id *master;
525 struct hci_conn *hcon = conn->hcon;
526
527 key = hci_find_link_key_type(hcon->hdev, conn->dst,
528 HCI_LK_SMP_LTK);
529 if (!key)
530 return 0;
531
532 if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND,
533 &hcon->pend))
534 return 1;
535
536 master = (void *) key->data;
537 hci_le_start_enc(hcon, master->ediv, master->rand,
538 key->val);
539 hcon->enc_key_size = key->pin_len;
540
541 return 1;
542
543}
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300544static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300545{
546 struct smp_cmd_security_req *rp = (void *) skb->data;
547 struct smp_cmd_pairing cp;
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300548 struct hci_conn *hcon = conn->hcon;
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300549 struct smp_chan *smp;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300550
551 BT_DBG("conn %p", conn);
552
Vinicius Costa Gomesfeb45eb2011-08-25 20:02:35 -0300553 hcon->pending_sec_level = BT_SECURITY_MEDIUM;
554
Vinicius Costa Gomes988c5992011-08-25 20:02:28 -0300555 if (smp_ltk_encrypt(conn))
556 return 0;
557
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -0300558 if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend))
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300559 return 0;
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300560
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300561 smp = smp_chan_create(conn);
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -0300562
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300563 skb_pull(skb, sizeof(*rp));
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300564
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300565 memset(&cp, 0, sizeof(cp));
Vinicius Costa Gomes54790f72011-07-07 18:59:38 -0300566 build_pairing_cmd(conn, &cp, NULL, rp->auth_req);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300567
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300568 smp->preq[0] = SMP_CMD_PAIRING_REQ;
569 memcpy(&smp->preq[1], &cp, sizeof(cp));
Anderson Brigliaf01ead32011-06-09 18:50:45 -0300570
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300571 smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300572
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300573 return 0;
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300574}
575
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300576int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
577{
Vinicius Costa Gomes3a0259b2011-06-09 18:50:43 -0300578 struct hci_conn *hcon = conn->hcon;
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300579 struct smp_chan *smp = conn->smp_chan;
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300580
Vinicius Costa Gomes3a0259b2011-06-09 18:50:43 -0300581 BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level);
582
Andre Guedes2e65c9d2011-06-30 19:20:56 -0300583 if (!lmp_host_le_capable(hcon->hdev))
584 return 1;
585
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300586 if (sec_level == BT_SECURITY_LOW)
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300587 return 1;
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300588
589 if (hcon->sec_level >= sec_level)
590 return 1;
591
Vinicius Costa Gomes988c5992011-08-25 20:02:28 -0300592 if (hcon->link_mode & HCI_LM_MASTER)
593 if (smp_ltk_encrypt(conn))
Vinicius Costa Gomes02bc7452011-07-07 18:59:41 -0300594 goto done;
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -0300595
596 if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend))
597 return 0;
598
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300599 smp = smp_chan_create(conn);
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -0300600
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -0300601 if (hcon->link_mode & HCI_LM_MASTER) {
602 struct smp_cmd_pairing cp;
Anderson Brigliaf01ead32011-06-09 18:50:45 -0300603
Vinicius Costa Gomes0fb4eb62011-08-25 20:02:27 -0300604 build_pairing_cmd(conn, &cp, NULL, SMP_AUTH_NONE);
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300605 smp->preq[0] = SMP_CMD_PAIRING_REQ;
606 memcpy(&smp->preq[1], &cp, sizeof(cp));
Anderson Brigliaf01ead32011-06-09 18:50:45 -0300607
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300608 smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
609 } else {
610 struct smp_cmd_security_req cp;
Vinicius Costa Gomes0fb4eb62011-08-25 20:02:27 -0300611 cp.auth_req = SMP_AUTH_NONE;
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300612 smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp);
613 }
614
Vinicius Costa Gomes02bc7452011-07-07 18:59:41 -0300615done:
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300616 hcon->pending_sec_level = sec_level;
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300617
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300618 return 0;
619}
620
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300621static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
622{
Vinicius Costa Gomes16b90832011-07-07 18:59:39 -0300623 struct smp_cmd_encrypt_info *rp = (void *) skb->data;
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300624 struct smp_chan *smp = conn->smp_chan;
Vinicius Costa Gomes16b90832011-07-07 18:59:39 -0300625
626 skb_pull(skb, sizeof(*rp));
627
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300628 memcpy(smp->tk, rp->ltk, sizeof(smp->tk));
Vinicius Costa Gomes16b90832011-07-07 18:59:39 -0300629
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300630 return 0;
631}
632
633static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
634{
Vinicius Costa Gomes16b90832011-07-07 18:59:39 -0300635 struct smp_cmd_master_ident *rp = (void *) skb->data;
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300636 struct smp_chan *smp = conn->smp_chan;
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300637
Vinicius Costa Gomes16b90832011-07-07 18:59:39 -0300638 skb_pull(skb, sizeof(*rp));
639
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300640 hci_add_ltk(conn->hcon->hdev, 1, conn->src, smp->smp_key_size,
641 rp->ediv, rp->rand, smp->tk);
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300642
643 smp_distribute_keys(conn, 1);
644
645 return 0;
646}
647
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300648int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
649{
650 __u8 code = skb->data[0];
651 __u8 reason;
652 int err = 0;
653
Andre Guedes2e65c9d2011-06-30 19:20:56 -0300654 if (!lmp_host_le_capable(conn->hcon->hdev)) {
655 err = -ENOTSUPP;
656 reason = SMP_PAIRING_NOTSUPP;
657 goto done;
658 }
659
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300660 skb_pull(skb, sizeof(code));
661
662 switch (code) {
663 case SMP_CMD_PAIRING_REQ:
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300664 reason = smp_cmd_pairing_req(conn, skb);
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300665 break;
666
667 case SMP_CMD_PAIRING_FAIL:
Brian Gix4f957a72011-11-23 08:28:36 -0800668 smp_failure(conn, skb->data[0], 0);
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300669 reason = 0;
670 err = -EPERM;
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300671 break;
672
673 case SMP_CMD_PAIRING_RSP:
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300674 reason = smp_cmd_pairing_rsp(conn, skb);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300675 break;
676
677 case SMP_CMD_SECURITY_REQ:
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300678 reason = smp_cmd_security_req(conn, skb);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300679 break;
680
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300681 case SMP_CMD_PAIRING_CONFIRM:
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300682 reason = smp_cmd_pairing_confirm(conn, skb);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300683 break;
684
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300685 case SMP_CMD_PAIRING_RANDOM:
Vinicius Costa Gomesda85e5e2011-06-09 18:50:53 -0300686 reason = smp_cmd_pairing_random(conn, skb);
Anderson Briglia88ba43b2011-06-09 18:50:42 -0300687 break;
688
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300689 case SMP_CMD_ENCRYPT_INFO:
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300690 reason = smp_cmd_encrypt_info(conn, skb);
691 break;
692
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300693 case SMP_CMD_MASTER_IDENT:
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300694 reason = smp_cmd_master_ident(conn, skb);
695 break;
696
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300697 case SMP_CMD_IDENT_INFO:
698 case SMP_CMD_IDENT_ADDR_INFO:
699 case SMP_CMD_SIGN_INFO:
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300700 /* Just ignored */
701 reason = 0;
702 break;
703
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300704 default:
705 BT_DBG("Unknown command code 0x%2.2x", code);
706
707 reason = SMP_CMD_NOTSUPP;
Vinicius Costa Gomes3a0259b2011-06-09 18:50:43 -0300708 err = -EOPNOTSUPP;
709 goto done;
710 }
711
712done:
713 if (reason)
Brian Gix4f957a72011-11-23 08:28:36 -0800714 smp_failure(conn, reason, 1);
Anderson Brigliaeb492e02011-06-09 18:50:40 -0300715
716 kfree_skb(skb);
717 return err;
718}
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300719
720int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
721{
722 struct smp_cmd_pairing *req, *rsp;
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300723 struct smp_chan *smp = conn->smp_chan;
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300724 __u8 *keydist;
725
726 BT_DBG("conn %p force %d", conn, force);
727
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -0300728 if (!test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend))
729 return 0;
730
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300731 rsp = (void *) &smp->prsp[1];
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300732
733 /* The responder sends its keys first */
734 if (!force && conn->hcon->out && (rsp->resp_key_dist & 0x07))
735 return 0;
736
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300737 req = (void *) &smp->preq[1];
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300738
739 if (conn->hcon->out) {
740 keydist = &rsp->init_key_dist;
741 *keydist &= req->init_key_dist;
742 } else {
743 keydist = &rsp->resp_key_dist;
744 *keydist &= req->resp_key_dist;
745 }
746
747
748 BT_DBG("keydist 0x%x", *keydist);
749
750 if (*keydist & SMP_DIST_ENC_KEY) {
751 struct smp_cmd_encrypt_info enc;
752 struct smp_cmd_master_ident ident;
753 __le16 ediv;
754
755 get_random_bytes(enc.ltk, sizeof(enc.ltk));
756 get_random_bytes(&ediv, sizeof(ediv));
757 get_random_bytes(ident.rand, sizeof(ident.rand));
758
759 smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc);
760
Vinicius Costa Gomes1c1def02011-09-05 14:31:30 -0300761 hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->smp_key_size,
Vinicius Costa Gomes726b4ff2011-07-08 18:31:45 -0300762 ediv, ident.rand, enc.ltk);
Vinicius Costa Gomes16b90832011-07-07 18:59:39 -0300763
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300764 ident.ediv = cpu_to_le16(ediv);
765
766 smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident);
767
768 *keydist &= ~SMP_DIST_ENC_KEY;
769 }
770
771 if (*keydist & SMP_DIST_ID_KEY) {
772 struct smp_cmd_ident_addr_info addrinfo;
773 struct smp_cmd_ident_info idinfo;
774
775 /* Send a dummy key */
776 get_random_bytes(idinfo.irk, sizeof(idinfo.irk));
777
778 smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo);
779
780 /* Just public address */
781 memset(&addrinfo, 0, sizeof(addrinfo));
782 bacpy(&addrinfo.bdaddr, conn->src);
783
784 smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo),
785 &addrinfo);
786
787 *keydist &= ~SMP_DIST_ID_KEY;
788 }
789
790 if (*keydist & SMP_DIST_SIGN) {
791 struct smp_cmd_sign_info sign;
792
793 /* Send a dummy key */
794 get_random_bytes(sign.csrk, sizeof(sign.csrk));
795
796 smp_send_cmd(conn, SMP_CMD_SIGN_INFO, sizeof(sign), &sign);
797
798 *keydist &= ~SMP_DIST_SIGN;
799 }
800
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -0300801 if (conn->hcon->out || force) {
802 clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend);
803 del_timer(&conn->security_timer);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -0300804 smp_chan_destroy(conn);
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -0300805 }
806
Vinicius Costa Gomes7034b912011-07-07 18:59:34 -0300807 return 0;
808}