Commit da85e5e5afeb72bb6e6b5192a2d252861fafc3e7
Committed by
Gustavo F. Padovan
1 parent
b8e66eacab
Exists in
master
and in
38 other branches
Bluetooth: Add support for Pairing features exchange
This patch implements a simple version of the SMP Pairing Features exchange procedure (Vol. 3 Part H, Section 2.3.5.1). For now, everything that would cause a Pairing Method different of Just Works to be chosen is rejected. Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@openbossa.org> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Showing 2 changed files with 54 additions and 53 deletions Side-by-side Diff
net/bluetooth/hci_event.c
net/bluetooth/smp.c
... | ... | @@ -181,6 +181,18 @@ |
181 | 181 | hci_send_acl(conn->hcon, skb, 0); |
182 | 182 | } |
183 | 183 | |
184 | +static __u8 seclevel_to_authreq(__u8 level) | |
185 | +{ | |
186 | + switch (level) { | |
187 | + case BT_SECURITY_HIGH: | |
188 | + /* Right now we don't support bonding */ | |
189 | + return SMP_AUTH_MITM; | |
190 | + | |
191 | + default: | |
192 | + return SMP_AUTH_NONE; | |
193 | + } | |
194 | +} | |
195 | + | |
184 | 196 | static void build_pairing_cmd(struct l2cap_conn *conn, |
185 | 197 | struct smp_cmd_pairing *cmd, __u8 authreq) |
186 | 198 | { |
... | ... | @@ -192,7 +204,7 @@ |
192 | 204 | cmd->auth_req = authreq; |
193 | 205 | } |
194 | 206 | |
195 | -static void smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) | |
207 | +static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) | |
196 | 208 | { |
197 | 209 | struct smp_cmd_pairing *rp = (void *) skb->data; |
198 | 210 | |
199 | 211 | |
... | ... | @@ -202,13 +214,12 @@ |
202 | 214 | memcpy(&conn->preq[1], rp, sizeof(*rp)); |
203 | 215 | skb_pull(skb, sizeof(*rp)); |
204 | 216 | |
205 | - rp->io_capability = 0x00; | |
206 | - rp->oob_flag = 0x00; | |
207 | - rp->max_key_size = 16; | |
208 | - rp->init_key_dist = 0x00; | |
209 | - rp->resp_key_dist = 0x00; | |
210 | - rp->auth_req &= (SMP_AUTH_BONDING | SMP_AUTH_MITM); | |
217 | + if (rp->oob_flag) | |
218 | + return SMP_OOB_NOT_AVAIL; | |
211 | 219 | |
220 | + /* We didn't start the pairing, so no requirements */ | |
221 | + build_pairing_cmd(conn, rp, SMP_AUTH_NONE); | |
222 | + | |
212 | 223 | /* Just works */ |
213 | 224 | memset(conn->tk, 0, sizeof(conn->tk)); |
214 | 225 | |
215 | 226 | |
... | ... | @@ -216,9 +227,11 @@ |
216 | 227 | memcpy(&conn->prsp[1], rp, sizeof(*rp)); |
217 | 228 | |
218 | 229 | smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(*rp), rp); |
230 | + | |
231 | + return 0; | |
219 | 232 | } |
220 | 233 | |
221 | -static void smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) | |
234 | +static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) | |
222 | 235 | { |
223 | 236 | struct smp_cmd_pairing *rp = (void *) skb->data; |
224 | 237 | struct smp_cmd_pairing_confirm cp; |
225 | 238 | |
226 | 239 | |
227 | 240 | |
228 | 241 | |
229 | 242 | |
... | ... | @@ -228,29 +241,34 @@ |
228 | 241 | |
229 | 242 | BT_DBG("conn %p", conn); |
230 | 243 | |
244 | + skb_pull(skb, sizeof(*rp)); | |
245 | + | |
246 | + if (rp->oob_flag) | |
247 | + return SMP_OOB_NOT_AVAIL; | |
248 | + | |
231 | 249 | /* Just works */ |
232 | 250 | memset(conn->tk, 0, sizeof(conn->tk)); |
233 | 251 | |
234 | 252 | conn->prsp[0] = SMP_CMD_PAIRING_RSP; |
235 | 253 | memcpy(&conn->prsp[1], rp, sizeof(*rp)); |
236 | - skb_pull(skb, sizeof(*rp)); | |
237 | 254 | |
238 | 255 | ret = smp_rand(conn->prnd); |
239 | 256 | if (ret) |
240 | - return; | |
257 | + return SMP_UNSPECIFIED; | |
241 | 258 | |
242 | 259 | ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp, 0, |
243 | 260 | conn->src, conn->hcon->dst_type, conn->dst, res); |
244 | 261 | if (ret) |
245 | - return; | |
262 | + return SMP_UNSPECIFIED; | |
246 | 263 | |
247 | 264 | swap128(res, cp.confirm_val); |
248 | 265 | |
249 | 266 | smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); |
267 | + | |
268 | + return 0; | |
250 | 269 | } |
251 | 270 | |
252 | -static void smp_cmd_pairing_confirm(struct l2cap_conn *conn, | |
253 | - struct sk_buff *skb) | |
271 | +static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb) | |
254 | 272 | { |
255 | 273 | struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm; |
256 | 274 | |
257 | 275 | |
258 | 276 | |
259 | 277 | |
... | ... | @@ -272,21 +290,23 @@ |
272 | 290 | |
273 | 291 | ret = smp_rand(conn->prnd); |
274 | 292 | if (ret) |
275 | - return; | |
293 | + return SMP_UNSPECIFIED; | |
276 | 294 | |
277 | 295 | ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp, |
278 | 296 | conn->hcon->dst_type, conn->dst, |
279 | 297 | 0, conn->src, res); |
280 | 298 | if (ret) |
281 | - return; | |
299 | + return SMP_CONFIRM_FAILED; | |
282 | 300 | |
283 | 301 | swap128(res, cp.confirm_val); |
284 | 302 | |
285 | 303 | smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); |
286 | 304 | } |
305 | + | |
306 | + return 0; | |
287 | 307 | } |
288 | 308 | |
289 | -static void smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) | |
309 | +static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) | |
290 | 310 | { |
291 | 311 | struct hci_conn *hcon = conn->hcon; |
292 | 312 | struct crypto_blkcipher *tfm = hcon->hdev->tfm; |
293 | 313 | |
294 | 314 | |
... | ... | @@ -307,19 +327,15 @@ |
307 | 327 | conn->hcon->dst_type, conn->dst, 0, conn->src, |
308 | 328 | res); |
309 | 329 | if (ret) |
310 | - return; | |
330 | + return SMP_UNSPECIFIED; | |
311 | 331 | |
312 | 332 | BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); |
313 | 333 | |
314 | 334 | swap128(res, confirm); |
315 | 335 | |
316 | 336 | if (memcmp(conn->pcnf, confirm, sizeof(conn->pcnf)) != 0) { |
317 | - struct smp_cmd_pairing_fail cp; | |
318 | - | |
319 | 337 | BT_ERR("Pairing failed (confirmation values mismatch)"); |
320 | - cp.reason = SMP_CONFIRM_FAILED; | |
321 | - smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(cp), &cp); | |
322 | - return; | |
338 | + return SMP_CONFIRM_FAILED; | |
323 | 339 | } |
324 | 340 | |
325 | 341 | if (conn->hcon->out) { |
326 | 342 | |
... | ... | @@ -341,9 +357,11 @@ |
341 | 357 | smp_s1(tfm, conn->tk, conn->prnd, random, key); |
342 | 358 | swap128(key, hcon->ltk); |
343 | 359 | } |
360 | + | |
361 | + return 0; | |
344 | 362 | } |
345 | 363 | |
346 | -static void smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) | |
364 | +static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) | |
347 | 365 | { |
348 | 366 | struct smp_cmd_security_req *rp = (void *) skb->data; |
349 | 367 | struct smp_cmd_pairing cp; |
350 | 368 | |
351 | 369 | |
352 | 370 | |
353 | 371 | |
354 | 372 | |
... | ... | @@ -352,36 +370,21 @@ |
352 | 370 | BT_DBG("conn %p", conn); |
353 | 371 | |
354 | 372 | if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) |
355 | - return; | |
373 | + return 0; | |
356 | 374 | |
357 | 375 | skb_pull(skb, sizeof(*rp)); |
376 | + | |
358 | 377 | memset(&cp, 0, sizeof(cp)); |
378 | + build_pairing_cmd(conn, &cp, rp->auth_req); | |
359 | 379 | |
360 | - cp.io_capability = 0x00; | |
361 | - cp.oob_flag = 0x00; | |
362 | - cp.max_key_size = 16; | |
363 | - cp.init_key_dist = 0x00; | |
364 | - cp.resp_key_dist = 0x00; | |
365 | - cp.auth_req = rp->auth_req & (SMP_AUTH_BONDING | SMP_AUTH_MITM); | |
366 | - | |
367 | 380 | conn->preq[0] = SMP_CMD_PAIRING_REQ; |
368 | 381 | memcpy(&conn->preq[1], &cp, sizeof(cp)); |
369 | 382 | |
370 | 383 | smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); |
371 | 384 | |
372 | 385 | set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); |
373 | -} | |
374 | 386 | |
375 | -static __u8 seclevel_to_authreq(__u8 level) | |
376 | -{ | |
377 | - switch (level) { | |
378 | - case BT_SECURITY_HIGH: | |
379 | - /* For now we don't support bonding */ | |
380 | - return SMP_AUTH_MITM; | |
381 | - | |
382 | - default: | |
383 | - return SMP_AUTH_NONE; | |
384 | - } | |
387 | + return 0; | |
385 | 388 | } |
386 | 389 | |
387 | 390 | int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) |
388 | 391 | |
... | ... | @@ -407,13 +410,8 @@ |
407 | 410 | |
408 | 411 | if (hcon->link_mode & HCI_LM_MASTER) { |
409 | 412 | struct smp_cmd_pairing cp; |
410 | - cp.io_capability = 0x00; | |
411 | - cp.oob_flag = 0x00; | |
412 | - cp.max_key_size = 16; | |
413 | - cp.init_key_dist = 0x00; | |
414 | - cp.resp_key_dist = 0x00; | |
415 | - cp.auth_req = authreq; | |
416 | 413 | |
414 | + build_pairing_cmd(conn, &cp, authreq); | |
417 | 415 | conn->preq[0] = SMP_CMD_PAIRING_REQ; |
418 | 416 | memcpy(&conn->preq[1], &cp, sizeof(cp)); |
419 | 417 | |
420 | 418 | |
421 | 419 | |
422 | 420 | |
423 | 421 | |
424 | 422 | |
... | ... | @@ -446,26 +444,28 @@ |
446 | 444 | |
447 | 445 | switch (code) { |
448 | 446 | case SMP_CMD_PAIRING_REQ: |
449 | - smp_cmd_pairing_req(conn, skb); | |
447 | + reason = smp_cmd_pairing_req(conn, skb); | |
450 | 448 | break; |
451 | 449 | |
452 | 450 | case SMP_CMD_PAIRING_FAIL: |
451 | + reason = 0; | |
452 | + err = -EPERM; | |
453 | 453 | break; |
454 | 454 | |
455 | 455 | case SMP_CMD_PAIRING_RSP: |
456 | - smp_cmd_pairing_rsp(conn, skb); | |
456 | + reason = smp_cmd_pairing_rsp(conn, skb); | |
457 | 457 | break; |
458 | 458 | |
459 | 459 | case SMP_CMD_SECURITY_REQ: |
460 | - smp_cmd_security_req(conn, skb); | |
460 | + reason = smp_cmd_security_req(conn, skb); | |
461 | 461 | break; |
462 | 462 | |
463 | 463 | case SMP_CMD_PAIRING_CONFIRM: |
464 | - smp_cmd_pairing_confirm(conn, skb); | |
464 | + reason = smp_cmd_pairing_confirm(conn, skb); | |
465 | 465 | break; |
466 | 466 | |
467 | 467 | case SMP_CMD_PAIRING_RANDOM: |
468 | - smp_cmd_pairing_random(conn, skb); | |
468 | + reason = smp_cmd_pairing_random(conn, skb); | |
469 | 469 | break; |
470 | 470 | |
471 | 471 | case SMP_CMD_ENCRYPT_INFO: |