diff --git a/include/bluetooth/conn.h b/include/bluetooth/conn.h index c1055e2a50f..64939582a14 100644 --- a/include/bluetooth/conn.h +++ b/include/bluetooth/conn.h @@ -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). */ diff --git a/include/bluetooth/l2cap.h b/include/bluetooth/l2cap.h index 2979a1a2624..d508484cc33 100644 --- a/include/bluetooth/l2cap.h +++ b/include/bluetooth/l2cap.h @@ -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 diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 4a203def480..15cad55f494 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -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); } diff --git a/net/bluetooth/l2cap_br.c b/net/bluetooth/l2cap_br.c index bd86d30b894..32b9fdf37a5 100644 --- a/net/bluetooth/l2cap_br.c +++ b/net/bluetooth/l2cap_br.c @@ -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 */