Bluetooth: Add handling for security level 0

So far bt_security_t has completely missed out on security level 0,
i.e. its actual values have been one lower than in the core
specification.

To properly introduce for the new level (which is only applicable for
BR/EDR) add proper tracking for each channel and server, and make the
channels inherit their required level from the respective server.

Change-Id: I9a2384d883017125c2c117880aa6e0ade30520e4
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
Johan Hedberg 2016-11-01 11:05:35 +02:00
parent 237455f77f
commit 9dc033cb84
4 changed files with 40 additions and 4 deletions

View file

@ -241,6 +241,8 @@ struct bt_conn *bt_conn_create_slave_le(const bt_addr_le_t *peer,
/** Security level. */
typedef enum __packed {
/** Only for BR/EDR special cases, like SDP */
BT_SECURITY_ZERO,
/** No encryption and no authentication. */
BT_SECURITY_LOW,
/** Encryption and no authentication (no MITM). */

View file

@ -206,6 +206,9 @@ struct bt_l2cap_server {
/** Server PSM */
uint16_t psm;
/** Required minimim security level */
bt_security_t sec_level;
/** Server accept callback
*
* This callback is called whenever a new incoming connection requires

View file

@ -474,6 +474,13 @@ int bt_l2cap_server_register(struct bt_l2cap_server *server)
return -EINVAL;
}
if (server->sec_level > BT_SECURITY_FIPS) {
return -EINVAL;
} else if (server->sec_level < BT_SECURITY_LOW) {
/* Level 0 is only applicable for BR/EDR */
server->sec_level = BT_SECURITY_LOW;
}
/* Check if given PSM is already in use */
if (l2cap_server_lookup_psm(server->psm)) {
BT_DBG("PSM already registered");
@ -624,6 +631,8 @@ static void le_conn_req(struct bt_l2cap *l2cap, uint8_t ident,
goto rsp;
}
chan->required_sec_level = server->sec_level;
if (l2cap_chan_add(conn, chan, l2cap_chan_destroy)) {
struct bt_l2cap_le_chan *ch = BT_L2CAP_LE_CHAN(chan);
@ -1348,6 +1357,12 @@ int bt_l2cap_chan_connect(struct bt_conn *conn, struct bt_l2cap_chan *chan,
}
#endif /* CONFIG_BLUETOOTH_BREDR */
if (chan->required_sec_level > BT_SECURITY_FIPS) {
return -EINVAL;
} else if (chan->required_sec_level == BT_SECURITY_ZERO) {
chan->required_sec_level = BT_SECURITY_LOW;
}
return l2cap_le_connect(conn, BT_L2CAP_LE_CHAN(chan), psm);
}

View file

@ -708,9 +708,9 @@ l2cap_br_conn_security(struct bt_l2cap_chan *chan, const uint16_t psm)
int check;
/* For SDP PSM there's no need to change existing security on link */
if (psm == L2CAP_BR_PSM_SDP) {
if (chan->required_sec_level == BT_SECURITY_ZERO) {
return L2CAP_CONN_SECURITY_PASSED;
};
}
/*
* No link key needed for legacy devices (pre 2.1) and when low security
@ -839,8 +839,8 @@ static void l2cap_br_conn_req(struct bt_l2cap_br *l2cap, uint8_t ident,
* Report security violation for non SDP channel without encryption when
* remote supports SSP.
*/
if (psm != L2CAP_BR_PSM_SDP && BT_FEAT_HOST_SSP(conn->br.features) &&
!conn->encrypt) {
if (server->sec_level != BT_SECURITY_ZERO &&
BT_FEAT_HOST_SSP(conn->br.features) && !conn->encrypt) {
result = BT_L2CAP_BR_ERR_SEC_BLOCK;
goto done;
}
@ -865,6 +865,8 @@ static void l2cap_br_conn_req(struct bt_l2cap_br *l2cap, uint8_t ident,
goto done;
}
chan->required_sec_level = server->sec_level;
l2cap_br_chan_add(conn, chan, l2cap_br_chan_destroy);
BR_CHAN(chan)->tx.cid = scid;
dcid = BR_CHAN(chan)->rx.cid;
@ -973,6 +975,13 @@ int bt_l2cap_br_server_register(struct bt_l2cap_server *server)
return -EINVAL;
}
if (server->sec_level > BT_SECURITY_FIPS) {
return -EINVAL;
} else if (server->sec_level == BT_SECURITY_ZERO &&
server->psm != L2CAP_BR_PSM_SDP) {
server->sec_level = BT_SECURITY_LOW;
}
/* Check if given PSM is already in use */
if (l2cap_br_server_lookup_psm(server->psm)) {
BT_DBG("PSM already registered");
@ -1361,6 +1370,13 @@ int bt_l2cap_br_chan_connect(struct bt_conn *conn, struct bt_l2cap_chan *chan,
return -EINVAL;
}
if (chan->required_sec_level > BT_SECURITY_FIPS) {
return -EINVAL;
} else if (chan->required_sec_level == BT_SECURITY_ZERO &&
psm != L2CAP_BR_PSM_SDP) {
chan->required_sec_level = BT_SECURITY_LOW;
}
switch (chan->state) {
case BT_L2CAP_CONNECTED:
/* Already connected */