summaryrefslogtreecommitdiffstats
path: root/net/bluetooth/l2cap.c
diff options
context:
space:
mode:
authorMarcel Holtmann2009-01-15 21:58:04 +0100
committerMarcel Holtmann2009-02-27 06:14:25 +0100
commit8c1b235594fbab9a13240a1dac12ea9fd99b6440 (patch)
treeeb137a23e0fd8199144a4c3e36902af411e44269 /net/bluetooth/l2cap.c
parentBluetooth: Fix SCO state handling for incoming connections (diff)
downloadkernel-qcow2-linux-8c1b235594fbab9a13240a1dac12ea9fd99b6440.tar.gz
kernel-qcow2-linux-8c1b235594fbab9a13240a1dac12ea9fd99b6440.tar.xz
kernel-qcow2-linux-8c1b235594fbab9a13240a1dac12ea9fd99b6440.zip
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 'net/bluetooth/l2cap.c')
-rw-r--r--net/bluetooth/l2cap.c134
1 files changed, 40 insertions, 94 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 123efb46d3f5..eadf09231866 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -263,12 +263,17 @@ static inline int l2cap_check_link_mode(struct sock *sk)
{
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
- if ((l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) ||
- (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE))
- return hci_conn_encrypt(conn->hcon);
+ if (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE)
+ return hci_conn_security(conn->hcon, BT_SECURITY_HIGH);
+
+ if (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT)
+ return hci_conn_security(conn->hcon, BT_SECURITY_MEDIUM);
if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH)
- return hci_conn_auth(conn->hcon);
+ return hci_conn_security(conn->hcon, BT_SECURITY_LOW);
+
+ if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001))
+ return hci_conn_security(conn->hcon, BT_SECURITY_SDP);
return 1;
}
@@ -803,6 +808,7 @@ static int l2cap_do_connect(struct sock *sk)
struct l2cap_conn *conn;
struct hci_conn *hcon;
struct hci_dev *hdev;
+ __u8 sec_level;
__u8 auth_type;
int err = 0;
@@ -815,21 +821,37 @@ static int l2cap_do_connect(struct sock *sk)
err = -ENOMEM;
- if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH ||
- l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT ||
- l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE) {
- if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001))
- auth_type = HCI_AT_NO_BONDING_MITM;
+ if (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE)
+ sec_level = BT_SECURITY_HIGH;
+ else if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001))
+ sec_level = BT_SECURITY_SDP;
+ else if (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT)
+ sec_level = BT_SECURITY_MEDIUM;
+ else
+ sec_level = BT_SECURITY_LOW;
+
+ if (sk->sk_type == SOCK_RAW) {
+ if (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE)
+ auth_type = HCI_AT_DEDICATED_BONDING_MITM;
+ else if (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT)
+ auth_type = HCI_AT_DEDICATED_BONDING;
else
- auth_type = HCI_AT_GENERAL_BONDING_MITM;
- } else {
- if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001))
auth_type = HCI_AT_NO_BONDING;
+ } else if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) {
+ if (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE)
+ auth_type = HCI_AT_NO_BONDING_MITM;
else
+ auth_type = HCI_AT_NO_BONDING;
+ } else {
+ if (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE)
+ auth_type = HCI_AT_GENERAL_BONDING_MITM;
+ else if (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT)
auth_type = HCI_AT_GENERAL_BONDING;
+ else
+ auth_type = HCI_AT_NO_BONDING;
}
- hcon = hci_connect(hdev, ACL_LINK, dst, auth_type);
+ hcon = hci_connect(hdev, ACL_LINK, dst, sec_level, auth_type);
if (!hcon)
goto done;
@@ -1402,11 +1424,6 @@ static void l2cap_chan_ready(struct sock *sk)
*/
parent->sk_data_ready(parent, 0);
}
-
- if (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE) {
- struct l2cap_conn *conn = l2cap_pi(sk)->conn;
- hci_conn_change_link_key(conn->hcon);
- }
}
/* Copy frame to all raw sockets on that connection */
@@ -2323,77 +2340,7 @@ static int l2cap_disconn_ind(struct hci_conn *hcon, u8 reason)
return 0;
}
-static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status)
-{
- struct l2cap_chan_list *l;
- struct l2cap_conn *conn = hcon->l2cap_data;
- struct sock *sk;
-
- if (!conn)
- return 0;
-
- l = &conn->chan_list;
-
- BT_DBG("conn %p", conn);
-
- read_lock(&l->lock);
-
- for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
- struct l2cap_pinfo *pi = l2cap_pi(sk);
-
- bh_lock_sock(sk);
-
- if ((pi->link_mode & (L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE)) &&
- !(hcon->link_mode & HCI_LM_ENCRYPT) &&
- !status) {
- bh_unlock_sock(sk);
- continue;
- }
-
- if (sk->sk_state == BT_CONNECT) {
- if (!status) {
- struct l2cap_conn_req req;
- req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
- req.psm = l2cap_pi(sk)->psm;
-
- l2cap_pi(sk)->ident = l2cap_get_ident(conn);
-
- l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
- L2CAP_CONN_REQ, sizeof(req), &req);
- } else {
- l2cap_sock_clear_timer(sk);
- l2cap_sock_set_timer(sk, HZ / 10);
- }
- } else if (sk->sk_state == BT_CONNECT2) {
- struct l2cap_conn_rsp rsp;
- __u16 result;
-
- if (!status) {
- sk->sk_state = BT_CONFIG;
- result = L2CAP_CR_SUCCESS;
- } else {
- sk->sk_state = BT_DISCONN;
- l2cap_sock_set_timer(sk, HZ / 10);
- result = L2CAP_CR_SEC_BLOCK;
- }
-
- rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
- rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
- rsp.result = cpu_to_le16(result);
- rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
- l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
- L2CAP_CONN_RSP, sizeof(rsp), &rsp);
- }
-
- bh_unlock_sock(sk);
- }
-
- read_unlock(&l->lock);
-
- return 0;
-}
-
-static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
+static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
{
struct l2cap_chan_list *l;
struct l2cap_conn *conn = hcon->l2cap_data;
@@ -2413,10 +2360,10 @@ static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
bh_lock_sock(sk);
- if ((pi->link_mode & (L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE)) &&
+ if (!status && encrypt == 0x00 &&
+ (pi->link_mode & L2CAP_LM_SECURE) &&
(sk->sk_state == BT_CONNECTED ||
- sk->sk_state == BT_CONFIG) &&
- !status && encrypt == 0x00) {
+ sk->sk_state == BT_CONFIG)) {
__l2cap_sock_close(sk, ECONNREFUSED);
bh_unlock_sock(sk);
continue;
@@ -2608,8 +2555,7 @@ static struct hci_proto l2cap_hci_proto = {
.connect_ind = l2cap_connect_ind,
.connect_cfm = l2cap_connect_cfm,
.disconn_ind = l2cap_disconn_ind,
- .auth_cfm = l2cap_auth_cfm,
- .encrypt_cfm = l2cap_encrypt_cfm,
+ .security_cfm = l2cap_security_cfm,
.recv_acldata = l2cap_recv_acldata
};