Bluetooth: SMP: Move re-encryption handling into the SMP module
Move initiating security functionality and LTK requesting into the SMP module so that SMP can track when the connection is in the encryption process Signed-off-by: Joakim Andersson <joakim.andersson@nordicsemi.no>
This commit is contained in:
parent
d50b1ac301
commit
eb6ae10745
4 changed files with 148 additions and 167 deletions
|
@ -1030,28 +1030,11 @@ static int start_security(struct bt_conn *conn)
|
|||
}
|
||||
#endif /* CONFIG_BT_BREDR */
|
||||
|
||||
switch (conn->role) {
|
||||
#if defined(CONFIG_BT_CENTRAL) && defined(CONFIG_BT_SMP)
|
||||
case BT_HCI_ROLE_MASTER:
|
||||
{
|
||||
if (!bt_smp_keys_check(conn)) {
|
||||
return bt_smp_send_pairing_req(conn);
|
||||
}
|
||||
/* LE SC LTK and legacy master LTK are stored in same place */
|
||||
return bt_conn_le_start_encryption(conn,
|
||||
conn->le.keys->ltk.rand,
|
||||
conn->le.keys->ltk.ediv,
|
||||
conn->le.keys->ltk.val,
|
||||
conn->le.keys->enc_size);
|
||||
}
|
||||
#endif /* CONFIG_BT_CENTRAL && CONFIG_BT_SMP */
|
||||
#if defined(CONFIG_BT_PERIPHERAL) && defined(CONFIG_BT_SMP)
|
||||
case BT_HCI_ROLE_SLAVE:
|
||||
return bt_smp_send_security_req(conn);
|
||||
#endif /* CONFIG_BT_PERIPHERAL && CONFIG_BT_SMP */
|
||||
default:
|
||||
return -EINVAL;
|
||||
if (IS_ENABLED(CONFIG_BT_SMP)) {
|
||||
return bt_smp_start_security(conn);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int bt_conn_set_security(struct bt_conn *conn, bt_security_t sec)
|
||||
|
|
|
@ -3211,18 +3211,36 @@ static void le_ltk_neg_reply(u16_t handle)
|
|||
}
|
||||
|
||||
cp = net_buf_add(buf, sizeof(*cp));
|
||||
cp->handle = handle;
|
||||
cp->handle = sys_cpu_to_le16(handle);
|
||||
|
||||
bt_hci_cmd_send(BT_HCI_OP_LE_LTK_REQ_NEG_REPLY, buf);
|
||||
}
|
||||
|
||||
static void le_ltk_reply(u16_t handle, u8_t *ltk)
|
||||
{
|
||||
struct bt_hci_cp_le_ltk_req_reply *cp;
|
||||
struct net_buf *buf;
|
||||
|
||||
buf = bt_hci_cmd_create(BT_HCI_OP_LE_LTK_REQ_REPLY,
|
||||
sizeof(*cp));
|
||||
if (!buf) {
|
||||
BT_ERR("Out of command buffers");
|
||||
return;
|
||||
}
|
||||
|
||||
cp = net_buf_add(buf, sizeof(*cp));
|
||||
cp->handle = sys_cpu_to_le16(handle);
|
||||
memcpy(cp->ltk, ltk, sizeof(cp->ltk));
|
||||
|
||||
bt_hci_cmd_send(BT_HCI_OP_LE_LTK_REQ_REPLY, buf);
|
||||
}
|
||||
|
||||
static void le_ltk_request(struct net_buf *buf)
|
||||
{
|
||||
struct bt_hci_evt_le_ltk_request *evt = (void *)buf->data;
|
||||
struct bt_hci_cp_le_ltk_req_reply *cp;
|
||||
struct bt_conn *conn;
|
||||
u16_t handle;
|
||||
u8_t tk[16];
|
||||
u8_t ltk[16];
|
||||
|
||||
handle = sys_le16_to_cpu(evt->handle);
|
||||
|
||||
|
@ -3234,92 +3252,12 @@ static void le_ltk_request(struct net_buf *buf)
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* if TK is present use it, that means pairing is in progress and
|
||||
* we should use new TK for encryption
|
||||
*
|
||||
* Both legacy STK and LE SC LTK have rand and ediv equal to zero.
|
||||
*/
|
||||
if (evt->rand == 0U && evt->ediv == 0U && bt_smp_get_tk(conn, tk)) {
|
||||
buf = bt_hci_cmd_create(BT_HCI_OP_LE_LTK_REQ_REPLY,
|
||||
sizeof(*cp));
|
||||
if (!buf) {
|
||||
BT_ERR("Out of command buffers");
|
||||
goto done;
|
||||
}
|
||||
|
||||
cp = net_buf_add(buf, sizeof(*cp));
|
||||
cp->handle = evt->handle;
|
||||
memcpy(cp->ltk, tk, sizeof(cp->ltk));
|
||||
|
||||
bt_hci_cmd_send(BT_HCI_OP_LE_LTK_REQ_REPLY, buf);
|
||||
goto done;
|
||||
if (bt_smp_request_ltk(conn, evt->rand, evt->ediv, ltk)) {
|
||||
le_ltk_reply(handle, ltk);
|
||||
} else {
|
||||
le_ltk_neg_reply(handle);
|
||||
}
|
||||
|
||||
if (!conn->le.keys) {
|
||||
conn->le.keys = bt_keys_find(BT_KEYS_LTK_P256, conn->id,
|
||||
&conn->le.dst);
|
||||
if (!conn->le.keys) {
|
||||
conn->le.keys = bt_keys_find(BT_KEYS_SLAVE_LTK,
|
||||
conn->id, &conn->le.dst);
|
||||
}
|
||||
}
|
||||
|
||||
if (conn->le.keys && (conn->le.keys->keys & BT_KEYS_LTK_P256) &&
|
||||
evt->rand == 0U && evt->ediv == 0U) {
|
||||
buf = bt_hci_cmd_create(BT_HCI_OP_LE_LTK_REQ_REPLY,
|
||||
sizeof(*cp));
|
||||
if (!buf) {
|
||||
BT_ERR("Out of command buffers");
|
||||
goto done;
|
||||
}
|
||||
|
||||
cp = net_buf_add(buf, sizeof(*cp));
|
||||
cp->handle = evt->handle;
|
||||
|
||||
/* use only enc_size bytes of key for encryption */
|
||||
memcpy(cp->ltk, conn->le.keys->ltk.val,
|
||||
conn->le.keys->enc_size);
|
||||
if (conn->le.keys->enc_size < sizeof(cp->ltk)) {
|
||||
(void)memset(cp->ltk + conn->le.keys->enc_size, 0,
|
||||
sizeof(cp->ltk) - conn->le.keys->enc_size);
|
||||
}
|
||||
|
||||
bt_hci_cmd_send(BT_HCI_OP_LE_LTK_REQ_REPLY, buf);
|
||||
goto done;
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_BT_SMP_SC_PAIR_ONLY)
|
||||
if (conn->le.keys && (conn->le.keys->keys & BT_KEYS_SLAVE_LTK) &&
|
||||
!memcmp(conn->le.keys->slave_ltk.rand, &evt->rand, 8) &&
|
||||
!memcmp(conn->le.keys->slave_ltk.ediv, &evt->ediv, 2)) {
|
||||
buf = bt_hci_cmd_create(BT_HCI_OP_LE_LTK_REQ_REPLY,
|
||||
sizeof(*cp));
|
||||
if (!buf) {
|
||||
BT_ERR("Out of command buffers");
|
||||
goto done;
|
||||
}
|
||||
|
||||
cp = net_buf_add(buf, sizeof(*cp));
|
||||
cp->handle = evt->handle;
|
||||
|
||||
/* use only enc_size bytes of key for encryption */
|
||||
memcpy(cp->ltk, conn->le.keys->slave_ltk.val,
|
||||
conn->le.keys->enc_size);
|
||||
if (conn->le.keys->enc_size < sizeof(cp->ltk)) {
|
||||
(void)memset(cp->ltk + conn->le.keys->enc_size, 0,
|
||||
sizeof(cp->ltk) - conn->le.keys->enc_size);
|
||||
}
|
||||
|
||||
bt_hci_cmd_send(BT_HCI_OP_LE_LTK_REQ_REPLY, buf);
|
||||
goto done;
|
||||
}
|
||||
#endif /* !CONFIG_BT_SMP_SC_PAIR_ONLY */
|
||||
|
||||
le_ltk_neg_reply(evt->handle);
|
||||
bt_smp_keys_reject(conn);
|
||||
|
||||
done:
|
||||
bt_conn_unref(conn);
|
||||
}
|
||||
#endif /* CONFIG_BT_SMP */
|
||||
|
|
|
@ -308,7 +308,7 @@ no_callbacks:
|
|||
static u8_t legacy_get_pair_method(struct bt_smp *smp, u8_t remote_io);
|
||||
#endif
|
||||
|
||||
bool bt_smp_keys_check(struct bt_conn *conn)
|
||||
static bool smp_keys_check(struct bt_conn *conn)
|
||||
{
|
||||
if (atomic_test_bit(conn->flags, BT_CONN_FORCE_PAIR)) {
|
||||
return false;
|
||||
|
@ -2556,8 +2556,91 @@ static struct bt_smp *smp_chan_get(struct bt_conn *conn)
|
|||
return CONTAINER_OF(chan, struct bt_smp, chan);
|
||||
}
|
||||
|
||||
bool bt_smp_request_ltk(struct bt_conn *conn, u64_t rand, u16_t ediv, u8_t *ltk)
|
||||
{
|
||||
struct bt_smp *smp;
|
||||
u8_t enc_size;
|
||||
|
||||
smp = smp_chan_get(conn);
|
||||
if (!smp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Both legacy STK and LE SC LTK have rand and ediv equal to zero.
|
||||
* If pairing is in progress use the TK for encryption.
|
||||
*/
|
||||
if (ediv == 0U && rand == 0U &&
|
||||
atomic_test_bit(smp->flags, SMP_FLAG_PAIRING) &&
|
||||
atomic_test_bit(smp->flags, SMP_FLAG_ENC_PENDING)) {
|
||||
enc_size = get_encryption_key_size(smp);
|
||||
|
||||
/*
|
||||
* We keep both legacy STK and LE SC LTK in TK.
|
||||
* Also use only enc_size bytes of key for encryption.
|
||||
*/
|
||||
memcpy(ltk, smp->tk, enc_size);
|
||||
if (enc_size < BT_SMP_MAX_ENC_KEY_SIZE) {
|
||||
(void)memset(ltk + enc_size, 0,
|
||||
BT_SMP_MAX_ENC_KEY_SIZE - enc_size);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!conn->le.keys) {
|
||||
conn->le.keys = bt_keys_find(BT_KEYS_LTK_P256, conn->id,
|
||||
&conn->le.dst);
|
||||
if (!conn->le.keys) {
|
||||
conn->le.keys = bt_keys_find(BT_KEYS_SLAVE_LTK,
|
||||
conn->id, &conn->le.dst);
|
||||
}
|
||||
}
|
||||
|
||||
if (ediv == 0U && rand == 0U &&
|
||||
conn->le.keys && (conn->le.keys->keys & BT_KEYS_LTK_P256)) {
|
||||
enc_size = conn->le.keys->enc_size;
|
||||
|
||||
memcpy(ltk, conn->le.keys->ltk.val, enc_size);
|
||||
if (enc_size < BT_SMP_MAX_ENC_KEY_SIZE) {
|
||||
(void)memset(ltk + enc_size, 0,
|
||||
BT_SMP_MAX_ENC_KEY_SIZE - enc_size);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_BT_SMP_SC_PAIR_ONLY)
|
||||
if (conn->le.keys && (conn->le.keys->keys & BT_KEYS_SLAVE_LTK) &&
|
||||
!memcmp(conn->le.keys->slave_ltk.rand, &rand, 8) &&
|
||||
!memcmp(conn->le.keys->slave_ltk.ediv, &ediv, 2)) {
|
||||
enc_size = conn->le.keys->enc_size;
|
||||
|
||||
memcpy(ltk, conn->le.keys->slave_ltk.val, enc_size);
|
||||
if (enc_size < BT_SMP_MAX_ENC_KEY_SIZE) {
|
||||
(void)memset(ltk + enc_size, 0,
|
||||
BT_SMP_MAX_ENC_KEY_SIZE - enc_size);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif /* !CONFIG_BT_SMP_SC_PAIR_ONLY */
|
||||
|
||||
if (atomic_test_bit(smp->flags, SMP_FLAG_SEC_REQ)) {
|
||||
/* Notify higher level that security failed if security was
|
||||
* initiated by slave.
|
||||
*/
|
||||
bt_conn_security_changed(smp->chan.chan.conn,
|
||||
BT_SECURITY_ERR_PIN_OR_KEY_MISSING);
|
||||
|
||||
}
|
||||
|
||||
smp_reset(smp);
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_PERIPHERAL)
|
||||
int bt_smp_send_security_req(struct bt_conn *conn)
|
||||
static int smp_send_security_req(struct bt_conn *conn)
|
||||
{
|
||||
struct bt_smp *smp;
|
||||
struct bt_smp_security_request *req;
|
||||
|
@ -2580,7 +2663,7 @@ int bt_smp_send_security_req(struct bt_conn *conn)
|
|||
}
|
||||
|
||||
/* early verify if required sec level if reachable */
|
||||
if (!(sec_level_reachable(conn) || bt_smp_keys_check(conn))) {
|
||||
if (!(sec_level_reachable(conn) || smp_keys_check(conn))) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -2752,7 +2835,7 @@ static u8_t sc_send_public_key(struct bt_smp *smp)
|
|||
}
|
||||
|
||||
#if defined(CONFIG_BT_CENTRAL)
|
||||
int bt_smp_send_pairing_req(struct bt_conn *conn)
|
||||
static int smp_send_pairing_req(struct bt_conn *conn)
|
||||
{
|
||||
struct bt_smp *smp;
|
||||
struct bt_smp_pairing *req;
|
||||
|
@ -3623,7 +3706,7 @@ static u8_t smp_security_request(struct bt_smp *smp, struct net_buf *buf)
|
|||
|
||||
return 0;
|
||||
pair:
|
||||
if (bt_smp_send_pairing_req(conn) < 0) {
|
||||
if (smp_send_pairing_req(conn) < 0) {
|
||||
return BT_SMP_ERR_UNSPECIFIED;
|
||||
}
|
||||
|
||||
|
@ -4985,6 +5068,33 @@ int bt_passkey_set(unsigned int passkey)
|
|||
}
|
||||
#endif /* CONFIG_BT_FIXED_PASSKEY */
|
||||
|
||||
int bt_smp_start_security(struct bt_conn *conn)
|
||||
{
|
||||
switch (conn->role) {
|
||||
#if defined(CONFIG_BT_CENTRAL)
|
||||
case BT_HCI_ROLE_MASTER:
|
||||
{
|
||||
if (!smp_keys_check(conn)) {
|
||||
return smp_send_pairing_req(conn);
|
||||
}
|
||||
|
||||
/* LE SC LTK and legacy master LTK are stored in same place */
|
||||
return bt_conn_le_start_encryption(conn,
|
||||
conn->le.keys->ltk.rand,
|
||||
conn->le.keys->ltk.ediv,
|
||||
conn->le.keys->ltk.val,
|
||||
conn->le.keys->enc_size);
|
||||
}
|
||||
#endif /* CONFIG_BT_CENTRAL && CONFIG_BT_SMP */
|
||||
#if defined(CONFIG_BT_PERIPHERAL)
|
||||
case BT_HCI_ROLE_SLAVE:
|
||||
return smp_send_security_req(conn);
|
||||
#endif /* CONFIG_BT_PERIPHERAL && CONFIG_BT_SMP */
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
void bt_smp_update_keys(struct bt_conn *conn)
|
||||
{
|
||||
struct bt_smp *smp;
|
||||
|
@ -5062,55 +5172,6 @@ void bt_smp_update_keys(struct bt_conn *conn)
|
|||
}
|
||||
}
|
||||
|
||||
bool bt_smp_get_tk(struct bt_conn *conn, u8_t *tk)
|
||||
{
|
||||
struct bt_smp *smp;
|
||||
u8_t enc_size;
|
||||
|
||||
smp = smp_chan_get(conn);
|
||||
if (!smp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!atomic_test_bit(smp->flags, SMP_FLAG_PAIRING)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!atomic_test_bit(smp->flags, SMP_FLAG_ENC_PENDING)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
enc_size = get_encryption_key_size(smp);
|
||||
|
||||
/*
|
||||
* We keep both legacy STK and LE SC LTK in TK.
|
||||
* Also use only enc_size bytes of key for encryption.
|
||||
*/
|
||||
memcpy(tk, smp->tk, enc_size);
|
||||
if (enc_size < sizeof(smp->tk)) {
|
||||
(void)memset(tk + enc_size, 0, sizeof(smp->tk) - enc_size);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void bt_smp_keys_reject(struct bt_conn *conn)
|
||||
{
|
||||
struct bt_smp *smp;
|
||||
|
||||
smp = smp_chan_get(conn);
|
||||
if (!smp) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (atomic_test_bit(smp->flags, SMP_FLAG_SEC_REQ)) {
|
||||
bt_conn_security_changed(smp->chan.chan.conn,
|
||||
BT_SECURITY_ERR_PIN_OR_KEY_MISSING);
|
||||
}
|
||||
|
||||
smp_reset(smp);
|
||||
}
|
||||
|
||||
static int bt_smp_accept(struct bt_conn *conn, struct bt_l2cap_chan **chan)
|
||||
{
|
||||
int i;
|
||||
|
|
|
@ -123,12 +123,11 @@ struct bt_smp_dhkey_check {
|
|||
u8_t e[16];
|
||||
} __packed;
|
||||
|
||||
int bt_smp_send_pairing_req(struct bt_conn *conn);
|
||||
int bt_smp_send_security_req(struct bt_conn *conn);
|
||||
int bt_smp_start_security(struct bt_conn *conn);
|
||||
bool bt_smp_request_ltk(struct bt_conn *conn, u64_t rand, u16_t ediv,
|
||||
u8_t *ltk);
|
||||
|
||||
void bt_smp_update_keys(struct bt_conn *conn);
|
||||
bool bt_smp_get_tk(struct bt_conn *conn, u8_t *tk);
|
||||
bool bt_smp_keys_check(struct bt_conn *conn);
|
||||
void bt_smp_keys_reject(struct bt_conn *conn);
|
||||
|
||||
int bt_smp_br_send_pairing_req(struct bt_conn *conn);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue