diff options
author | Vinicius Costa Gomes <vinicius.gomes@openbossa.org> | 2011-07-07 17:59:34 -0400 |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-07-08 16:07:43 -0400 |
commit | 7034b911af1aa571995b56db3ed71a25daf00373 (patch) | |
tree | 89325f75fef679c8d6657ee6d971aa36823cc962 /net/bluetooth/smp.c | |
parent | fadd192e81b0a8d8086531b8c11bd88b311b68c2 (diff) |
Bluetooth: Add support for SMP phase 3 (key distribution)
This adds support for generating and distributing all the keys
specified in the third phase of SMP.
This will make possible to re-establish secure connections, resolve
private addresses and sign commands.
For now, the values generated are random.
Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@openbossa.org>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'net/bluetooth/smp.c')
-rw-r--r-- | net/bluetooth/smp.c | 114 |
1 files changed, 112 insertions, 2 deletions
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index ba55bd4b5dda..82443b95f24e 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c | |||
@@ -202,8 +202,8 @@ static void build_pairing_cmd(struct l2cap_conn *conn, | |||
202 | cmd->io_capability = conn->hcon->io_capability; | 202 | cmd->io_capability = conn->hcon->io_capability; |
203 | cmd->oob_flag = SMP_OOB_NOT_PRESENT; | 203 | cmd->oob_flag = SMP_OOB_NOT_PRESENT; |
204 | cmd->max_key_size = SMP_MAX_ENC_KEY_SIZE; | 204 | cmd->max_key_size = SMP_MAX_ENC_KEY_SIZE; |
205 | cmd->init_key_dist = 0x00; | 205 | cmd->init_key_dist = SMP_DIST_ENC_KEY | SMP_DIST_ID_KEY | SMP_DIST_SIGN; |
206 | cmd->resp_key_dist = 0x00; | 206 | cmd->resp_key_dist = SMP_DIST_ENC_KEY | SMP_DIST_ID_KEY | SMP_DIST_SIGN; |
207 | cmd->auth_req = authreq; | 207 | cmd->auth_req = authreq; |
208 | } | 208 | } |
209 | 209 | ||
@@ -474,6 +474,26 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) | |||
474 | return 0; | 474 | return 0; |
475 | } | 475 | } |
476 | 476 | ||
477 | static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb) | ||
478 | { | ||
479 | BT_DBG("conn %p", conn); | ||
480 | /* FIXME: store the ltk */ | ||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) | ||
485 | { | ||
486 | struct smp_cmd_pairing *paircmd = (void *) &conn->prsp[1]; | ||
487 | u8 keydist = paircmd->init_key_dist; | ||
488 | |||
489 | BT_DBG("keydist 0x%x", keydist); | ||
490 | /* FIXME: store ediv and rand */ | ||
491 | |||
492 | smp_distribute_keys(conn, 1); | ||
493 | |||
494 | return 0; | ||
495 | } | ||
496 | |||
477 | int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) | 497 | int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) |
478 | { | 498 | { |
479 | __u8 code = skb->data[0]; | 499 | __u8 code = skb->data[0]; |
@@ -521,10 +541,20 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) | |||
521 | break; | 541 | break; |
522 | 542 | ||
523 | case SMP_CMD_ENCRYPT_INFO: | 543 | case SMP_CMD_ENCRYPT_INFO: |
544 | reason = smp_cmd_encrypt_info(conn, skb); | ||
545 | break; | ||
546 | |||
524 | case SMP_CMD_MASTER_IDENT: | 547 | case SMP_CMD_MASTER_IDENT: |
548 | reason = smp_cmd_master_ident(conn, skb); | ||
549 | break; | ||
550 | |||
525 | case SMP_CMD_IDENT_INFO: | 551 | case SMP_CMD_IDENT_INFO: |
526 | case SMP_CMD_IDENT_ADDR_INFO: | 552 | case SMP_CMD_IDENT_ADDR_INFO: |
527 | case SMP_CMD_SIGN_INFO: | 553 | case SMP_CMD_SIGN_INFO: |
554 | /* Just ignored */ | ||
555 | reason = 0; | ||
556 | break; | ||
557 | |||
528 | default: | 558 | default: |
529 | BT_DBG("Unknown command code 0x%2.2x", code); | 559 | BT_DBG("Unknown command code 0x%2.2x", code); |
530 | 560 | ||
@@ -541,3 +571,83 @@ done: | |||
541 | kfree_skb(skb); | 571 | kfree_skb(skb); |
542 | return err; | 572 | return err; |
543 | } | 573 | } |
574 | |||
575 | int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) | ||
576 | { | ||
577 | struct smp_cmd_pairing *req, *rsp; | ||
578 | __u8 *keydist; | ||
579 | |||
580 | BT_DBG("conn %p force %d", conn, force); | ||
581 | |||
582 | if (IS_ERR(conn->hcon->hdev->tfm)) | ||
583 | return PTR_ERR(conn->hcon->hdev->tfm); | ||
584 | |||
585 | rsp = (void *) &conn->prsp[1]; | ||
586 | |||
587 | /* The responder sends its keys first */ | ||
588 | if (!force && conn->hcon->out && (rsp->resp_key_dist & 0x07)) | ||
589 | return 0; | ||
590 | |||
591 | req = (void *) &conn->preq[1]; | ||
592 | |||
593 | if (conn->hcon->out) { | ||
594 | keydist = &rsp->init_key_dist; | ||
595 | *keydist &= req->init_key_dist; | ||
596 | } else { | ||
597 | keydist = &rsp->resp_key_dist; | ||
598 | *keydist &= req->resp_key_dist; | ||
599 | } | ||
600 | |||
601 | |||
602 | BT_DBG("keydist 0x%x", *keydist); | ||
603 | |||
604 | if (*keydist & SMP_DIST_ENC_KEY) { | ||
605 | struct smp_cmd_encrypt_info enc; | ||
606 | struct smp_cmd_master_ident ident; | ||
607 | __le16 ediv; | ||
608 | |||
609 | get_random_bytes(enc.ltk, sizeof(enc.ltk)); | ||
610 | get_random_bytes(&ediv, sizeof(ediv)); | ||
611 | get_random_bytes(ident.rand, sizeof(ident.rand)); | ||
612 | |||
613 | smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc); | ||
614 | |||
615 | ident.ediv = cpu_to_le16(ediv); | ||
616 | |||
617 | smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident); | ||
618 | |||
619 | *keydist &= ~SMP_DIST_ENC_KEY; | ||
620 | } | ||
621 | |||
622 | if (*keydist & SMP_DIST_ID_KEY) { | ||
623 | struct smp_cmd_ident_addr_info addrinfo; | ||
624 | struct smp_cmd_ident_info idinfo; | ||
625 | |||
626 | /* Send a dummy key */ | ||
627 | get_random_bytes(idinfo.irk, sizeof(idinfo.irk)); | ||
628 | |||
629 | smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo); | ||
630 | |||
631 | /* Just public address */ | ||
632 | memset(&addrinfo, 0, sizeof(addrinfo)); | ||
633 | bacpy(&addrinfo.bdaddr, conn->src); | ||
634 | |||
635 | smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo), | ||
636 | &addrinfo); | ||
637 | |||
638 | *keydist &= ~SMP_DIST_ID_KEY; | ||
639 | } | ||
640 | |||
641 | if (*keydist & SMP_DIST_SIGN) { | ||
642 | struct smp_cmd_sign_info sign; | ||
643 | |||
644 | /* Send a dummy key */ | ||
645 | get_random_bytes(sign.csrk, sizeof(sign.csrk)); | ||
646 | |||
647 | smp_send_cmd(conn, SMP_CMD_SIGN_INFO, sizeof(sign), &sign); | ||
648 | |||
649 | *keydist &= ~SMP_DIST_SIGN; | ||
650 | } | ||
651 | |||
652 | return 0; | ||
653 | } | ||