diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2009-01-15 15:58:04 -0500 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2009-02-27 00:14:25 -0500 |
commit | 8c1b235594fbab9a13240a1dac12ea9fd99b6440 (patch) | |
tree | eb137a23e0fd8199144a4c3e36902af411e44269 /include/net/bluetooth | |
parent | c89b6e6bda4c8021195778f47567d0cc9dbfe7ec (diff) |
Bluetooth: Add enhanced security model for Simple Pairing
The current security model is based around the flags AUTH, ENCRYPT and
SECURE. Starting with support for the Bluetooth 2.1 specification this is
no longer sufficient. The different security levels are now defined as
SDP, LOW, MEDIUM and SECURE.
Previously it was possible to set each security independently, but this
actually doesn't make a lot of sense. For Bluetooth the encryption depends
on a previous successful authentication. Also you can only update your
existing link key if you successfully created at least one before. And of
course the update of link keys without having proper encryption in place
is a security issue.
The new security levels from the Bluetooth 2.1 specification are now
used internally. All old settings are mapped to the new values and this
way it ensures that old applications still work. The only limitation
is that it is no longer possible to set authentication without also
enabling encryption. No application should have done this anyway since
this is actually a security issue. Without encryption the integrity of
the authentication can't be guaranteed.
As default for a new L2CAP or RFCOMM connection, the LOW security level
is used. The only exception here are the service discovery sessions on
PSM 1 where SDP level is used. To have similar security strength as with
a Bluetooth 2.0 and before combination key, the MEDIUM level should be
used. This is according to the Bluetooth specification. The MEDIUM level
will not require any kind of man-in-the-middle (MITM) protection. Only
the HIGH security level will require this.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'include/net/bluetooth')
-rw-r--r-- | include/net/bluetooth/bluetooth.h | 9 | ||||
-rw-r--r-- | include/net/bluetooth/hci_core.h | 56 |
2 files changed, 42 insertions, 23 deletions
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 847e9e6df08b..3ad5390a4dd5 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h | |||
@@ -53,6 +53,15 @@ | |||
53 | #define SOL_SCO 17 | 53 | #define SOL_SCO 17 |
54 | #define SOL_RFCOMM 18 | 54 | #define SOL_RFCOMM 18 |
55 | 55 | ||
56 | #define BT_SECURITY 4 | ||
57 | struct bt_security { | ||
58 | __u8 level; | ||
59 | }; | ||
60 | #define BT_SECURITY_SDP 0 | ||
61 | #define BT_SECURITY_LOW 1 | ||
62 | #define BT_SECURITY_MEDIUM 2 | ||
63 | #define BT_SECURITY_HIGH 3 | ||
64 | |||
56 | #define BT_DEFER_SETUP 7 | 65 | #define BT_DEFER_SETUP 7 |
57 | 66 | ||
58 | #define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg) | 67 | #define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg) |
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 46a43b721dd6..4b14972c1694 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h | |||
@@ -169,6 +169,7 @@ struct hci_conn { | |||
169 | __u16 link_policy; | 169 | __u16 link_policy; |
170 | __u32 link_mode; | 170 | __u32 link_mode; |
171 | __u8 auth_type; | 171 | __u8 auth_type; |
172 | __u8 sec_level; | ||
172 | __u8 power_save; | 173 | __u8 power_save; |
173 | unsigned long pend; | 174 | unsigned long pend; |
174 | 175 | ||
@@ -325,12 +326,11 @@ int hci_conn_del(struct hci_conn *conn); | |||
325 | void hci_conn_hash_flush(struct hci_dev *hdev); | 326 | void hci_conn_hash_flush(struct hci_dev *hdev); |
326 | void hci_conn_check_pending(struct hci_dev *hdev); | 327 | void hci_conn_check_pending(struct hci_dev *hdev); |
327 | 328 | ||
328 | struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 auth_type); | 329 | struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type); |
329 | int hci_conn_check_link_mode(struct hci_conn *conn); | 330 | int hci_conn_check_link_mode(struct hci_conn *conn); |
330 | int hci_conn_auth(struct hci_conn *conn); | 331 | int hci_conn_security(struct hci_conn *conn, __u8 sec_level); |
331 | int hci_conn_encrypt(struct hci_conn *conn); | ||
332 | int hci_conn_change_link_key(struct hci_conn *conn); | 332 | int hci_conn_change_link_key(struct hci_conn *conn); |
333 | int hci_conn_switch_role(struct hci_conn *conn, uint8_t role); | 333 | int hci_conn_switch_role(struct hci_conn *conn, __u8 role); |
334 | 334 | ||
335 | void hci_conn_enter_active_mode(struct hci_conn *conn); | 335 | void hci_conn_enter_active_mode(struct hci_conn *conn); |
336 | void hci_conn_enter_sniff_mode(struct hci_conn *conn); | 336 | void hci_conn_enter_sniff_mode(struct hci_conn *conn); |
@@ -470,26 +470,25 @@ void hci_conn_del_sysfs(struct hci_conn *conn); | |||
470 | 470 | ||
471 | /* ----- HCI protocols ----- */ | 471 | /* ----- HCI protocols ----- */ |
472 | struct hci_proto { | 472 | struct hci_proto { |
473 | char *name; | 473 | char *name; |
474 | unsigned int id; | 474 | unsigned int id; |
475 | unsigned long flags; | 475 | unsigned long flags; |
476 | 476 | ||
477 | void *priv; | 477 | void *priv; |
478 | 478 | ||
479 | int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type); | 479 | int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type); |
480 | int (*connect_cfm) (struct hci_conn *conn, __u8 status); | 480 | int (*connect_cfm) (struct hci_conn *conn, __u8 status); |
481 | int (*disconn_ind) (struct hci_conn *conn, __u8 reason); | 481 | int (*disconn_ind) (struct hci_conn *conn, __u8 reason); |
482 | int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb, __u16 flags); | 482 | int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb, __u16 flags); |
483 | int (*recv_scodata) (struct hci_conn *conn, struct sk_buff *skb); | 483 | int (*recv_scodata) (struct hci_conn *conn, struct sk_buff *skb); |
484 | int (*auth_cfm) (struct hci_conn *conn, __u8 status); | 484 | int (*security_cfm) (struct hci_conn *conn, __u8 status, __u8 encrypt); |
485 | int (*encrypt_cfm) (struct hci_conn *conn, __u8 status, __u8 encrypt); | ||
486 | }; | 485 | }; |
487 | 486 | ||
488 | static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type) | 487 | static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type) |
489 | { | 488 | { |
490 | register struct hci_proto *hp; | 489 | register struct hci_proto *hp; |
491 | int mask = 0; | 490 | int mask = 0; |
492 | 491 | ||
493 | hp = hci_proto[HCI_PROTO_L2CAP]; | 492 | hp = hci_proto[HCI_PROTO_L2CAP]; |
494 | if (hp && hp->connect_ind) | 493 | if (hp && hp->connect_ind) |
495 | mask |= hp->connect_ind(hdev, bdaddr, type); | 494 | mask |= hp->connect_ind(hdev, bdaddr, type); |
@@ -530,14 +529,20 @@ static inline void hci_proto_disconn_ind(struct hci_conn *conn, __u8 reason) | |||
530 | static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status) | 529 | static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status) |
531 | { | 530 | { |
532 | register struct hci_proto *hp; | 531 | register struct hci_proto *hp; |
532 | __u8 encrypt; | ||
533 | |||
534 | if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) | ||
535 | return; | ||
536 | |||
537 | encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00; | ||
533 | 538 | ||
534 | hp = hci_proto[HCI_PROTO_L2CAP]; | 539 | hp = hci_proto[HCI_PROTO_L2CAP]; |
535 | if (hp && hp->auth_cfm) | 540 | if (hp && hp->security_cfm) |
536 | hp->auth_cfm(conn, status); | 541 | hp->security_cfm(conn, status, encrypt); |
537 | 542 | ||
538 | hp = hci_proto[HCI_PROTO_SCO]; | 543 | hp = hci_proto[HCI_PROTO_SCO]; |
539 | if (hp && hp->auth_cfm) | 544 | if (hp && hp->security_cfm) |
540 | hp->auth_cfm(conn, status); | 545 | hp->security_cfm(conn, status, encrypt); |
541 | } | 546 | } |
542 | 547 | ||
543 | static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status, __u8 encrypt) | 548 | static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status, __u8 encrypt) |
@@ -545,12 +550,12 @@ static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status, __u | |||
545 | register struct hci_proto *hp; | 550 | register struct hci_proto *hp; |
546 | 551 | ||
547 | hp = hci_proto[HCI_PROTO_L2CAP]; | 552 | hp = hci_proto[HCI_PROTO_L2CAP]; |
548 | if (hp && hp->encrypt_cfm) | 553 | if (hp && hp->security_cfm) |
549 | hp->encrypt_cfm(conn, status, encrypt); | 554 | hp->security_cfm(conn, status, encrypt); |
550 | 555 | ||
551 | hp = hci_proto[HCI_PROTO_SCO]; | 556 | hp = hci_proto[HCI_PROTO_SCO]; |
552 | if (hp && hp->encrypt_cfm) | 557 | if (hp && hp->security_cfm) |
553 | hp->encrypt_cfm(conn, status, encrypt); | 558 | hp->security_cfm(conn, status, encrypt); |
554 | } | 559 | } |
555 | 560 | ||
556 | int hci_register_proto(struct hci_proto *hproto); | 561 | int hci_register_proto(struct hci_proto *hproto); |
@@ -562,8 +567,7 @@ struct hci_cb { | |||
562 | 567 | ||
563 | char *name; | 568 | char *name; |
564 | 569 | ||
565 | void (*auth_cfm) (struct hci_conn *conn, __u8 status); | 570 | void (*security_cfm) (struct hci_conn *conn, __u8 status, __u8 encrypt); |
566 | void (*encrypt_cfm) (struct hci_conn *conn, __u8 status, __u8 encrypt); | ||
567 | void (*key_change_cfm) (struct hci_conn *conn, __u8 status); | 571 | void (*key_change_cfm) (struct hci_conn *conn, __u8 status); |
568 | void (*role_switch_cfm) (struct hci_conn *conn, __u8 status, __u8 role); | 572 | void (*role_switch_cfm) (struct hci_conn *conn, __u8 status, __u8 role); |
569 | }; | 573 | }; |
@@ -571,14 +575,20 @@ struct hci_cb { | |||
571 | static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status) | 575 | static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status) |
572 | { | 576 | { |
573 | struct list_head *p; | 577 | struct list_head *p; |
578 | __u8 encrypt; | ||
574 | 579 | ||
575 | hci_proto_auth_cfm(conn, status); | 580 | hci_proto_auth_cfm(conn, status); |
576 | 581 | ||
582 | if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) | ||
583 | return; | ||
584 | |||
585 | encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00; | ||
586 | |||
577 | read_lock_bh(&hci_cb_list_lock); | 587 | read_lock_bh(&hci_cb_list_lock); |
578 | list_for_each(p, &hci_cb_list) { | 588 | list_for_each(p, &hci_cb_list) { |
579 | struct hci_cb *cb = list_entry(p, struct hci_cb, list); | 589 | struct hci_cb *cb = list_entry(p, struct hci_cb, list); |
580 | if (cb->auth_cfm) | 590 | if (cb->security_cfm) |
581 | cb->auth_cfm(conn, status); | 591 | cb->security_cfm(conn, status, encrypt); |
582 | } | 592 | } |
583 | read_unlock_bh(&hci_cb_list_lock); | 593 | read_unlock_bh(&hci_cb_list_lock); |
584 | } | 594 | } |
@@ -592,8 +602,8 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status, __u8 encr | |||
592 | read_lock_bh(&hci_cb_list_lock); | 602 | read_lock_bh(&hci_cb_list_lock); |
593 | list_for_each(p, &hci_cb_list) { | 603 | list_for_each(p, &hci_cb_list) { |
594 | struct hci_cb *cb = list_entry(p, struct hci_cb, list); | 604 | struct hci_cb *cb = list_entry(p, struct hci_cb, list); |
595 | if (cb->encrypt_cfm) | 605 | if (cb->security_cfm) |
596 | cb->encrypt_cfm(conn, status, encrypt); | 606 | cb->security_cfm(conn, status, encrypt); |
597 | } | 607 | } |
598 | read_unlock_bh(&hci_cb_list_lock); | 608 | read_unlock_bh(&hci_cb_list_lock); |
599 | } | 609 | } |