/**
* @file smp.c
* Security Manager Protocol implementation
*/
/*
* Copyright (c) 2017 Nordic Semiconductor ASA
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/zephyr.h>
#include <stddef.h>
#include <errno.h>
#include <string.h>
#include <zephyr/sys/atomic.h>
#include <zephyr/sys/util.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/debug/stack.h>
#include <zephyr/net/buf.h>
#include <zephyr/bluetooth/hci.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/buf.h>
#include <tinycrypt/constants.h>
#include <tinycrypt/aes.h>
#include <tinycrypt/utils.h>
#include <tinycrypt/cmac_mode.h>
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_SMP)
#define LOG_MODULE_NAME bt_smp
#include "common/log.h"
#include "hci_core.h"
#include "ecc.h"
#include "keys.h"
#include "conn_internal.h"
#include "l2cap_internal.h"
#include "smp.h"
#define SMP_TIMEOUT K_SECONDS(30)
#if defined(CONFIG_BT_SIGNING)
#define SIGN_DIST BT_SMP_DIST_SIGN
#else
#define SIGN_DIST 0
#endif
#if defined(CONFIG_BT_PRIVACY)
#define ID_DIST BT_SMP_DIST_ID_KEY
#else
#define ID_DIST 0
#endif
#if defined(CONFIG_BT_BREDR)
#define LINK_DIST BT_SMP_DIST_LINK_KEY
#else
#define LINK_DIST 0
#endif
#define RECV_KEYS (BT_SMP_DIST_ENC_KEY | BT_SMP_DIST_ID_KEY | SIGN_DIST |\
LINK_DIST)
#define SEND_KEYS (BT_SMP_DIST_ENC_KEY | ID_DIST | SIGN_DIST | LINK_DIST)
#define RECV_KEYS_SC (RECV_KEYS & ~(BT_SMP_DIST_ENC_KEY))
#define SEND_KEYS_SC (SEND_KEYS & ~(BT_SMP_DIST_ENC_KEY))
#define BR_RECV_KEYS_SC (RECV_KEYS & ~(LINK_DIST))
#define BR_SEND_KEYS_SC (SEND_KEYS & ~(LINK_DIST))
#define BT_SMP_AUTH_MASK 0x07
#if defined(CONFIG_BT_BONDABLE)
#define BT_SMP_AUTH_BONDING_FLAGS BT_SMP_AUTH_BONDING
#else
#define BT_SMP_AUTH_BONDING_FLAGS 0
#endif /* CONFIG_BT_BONDABLE */
#if defined(CONFIG_BT_BREDR)
#define BT_SMP_AUTH_MASK_SC 0x2f
#if defined(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY)
#define BT_SMP_AUTH_DEFAULT (BT_SMP_AUTH_BONDING_FLAGS | BT_SMP_AUTH_CT2)
#else
#define BT_SMP_AUTH_DEFAULT (BT_SMP_AUTH_BONDING_FLAGS | BT_SMP_AUTH_CT2 |\
BT_SMP_AUTH_SC)
#endif /* CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY */
#else
#define BT_SMP_AUTH_MASK_SC 0x0f
#if defined(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY)
#define BT_SMP_AUTH_DEFAULT (BT_SMP_AUTH_BONDING_FLAGS)
#else
#define BT_SMP_AUTH_DEFAULT (BT_SMP_AUTH_BONDING_FLAGS | BT_SMP_AUTH_SC)
#endif /* CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY */
#endif /* CONFIG_BT_BREDR */
enum pairing_method {
JUST_WORKS, /* JustWorks pairing */
PASSKEY_INPUT, /* Passkey Entry input */
PASSKEY_DISPLAY, /* Passkey Entry display */
PASSKEY_CONFIRM, /* Passkey confirm */
PASSKEY_ROLE, /* Passkey Entry depends on role */
LE_SC_OOB, /* LESC Out of Band */
LEGACY_OOB, /* Legacy Out of Band */
};
enum {
SMP_FLAG_CFM_DELAYED, /* if confirm should be send when TK is valid */
SMP_FLAG_ENC_PENDING, /* if waiting for an encryption change event */
SMP_FLAG_KEYS_DISTR, /* if keys distribution phase is in progress */
SMP_FLAG_PAIRING, /* if pairing is in progress */
SMP_FLAG_TIMEOUT, /* if SMP timeout occurred */
SMP_FLAG_SC, /* if LE Secure Connections is used */
SMP_FLAG_PKEY_SEND, /* if should send Public Key when available */
SMP_FLAG_DHKEY_PENDING, /* if waiting for local DHKey */
SMP_FLAG_DHKEY_GEN, /* if generating DHKey */
SMP_FLAG_DHKEY_SEND, /* if should generate and send DHKey Check */
SMP_FLAG_USER, /* if waiting for user input */
SMP_FLAG_DISPLAY, /* if display_passkey() callback was called */
SMP_FLAG_OOB_PENDING, /* if waiting for OOB data */
SMP_FLAG_BOND, /* if bonding */
SMP_FLAG_SC_DEBUG_KEY, /* if Secure Connection are using debug key */
SMP_FLAG_SEC_REQ, /* if Security Request was sent/received */
SMP_FLAG_DHCHECK_WAIT, /* if waiting for remote DHCheck (as periph) */
SMP_FLAG_DERIVE_LK, /* if Link Key should be derived */
SMP_FLAG_BR_CONNECTED, /* if BR/EDR channel is connected */
SMP_FLAG_BR_PAIR, /* if should start BR/EDR pairing */
SMP_FLAG_CT2, /* if should use H7 for keys derivation */
/* Total number of flags - must be at the end */
SMP_NUM_FLAGS,
};
/* SMP channel specific context */
struct bt_smp {
/* Commands that remote is allowed to send */
ATOMIC_DEFINE(allowed_cmds, BT_SMP_NUM_CMDS);
/* Flags for SMP state machine */
ATOMIC_DEFINE(flags, SMP_NUM_FLAGS);
/* Type of method used for pairing */
uint8_t method;
/* Pairing Request PDU */
uint8_t preq[7];
/* Pairing Response PDU */
uint8_t prsp[7];
/* Pairing Confirm PDU */
uint8_t pcnf[16];
/* Local random number */
uint8_t prnd[16];
/* Remote random number */
uint8_t rrnd[16];
/* Temporary key */
uint8_t tk[16];
/* Remote Public Key for LE SC */
uint8_t pkey[BT_PUB_KEY_LEN];
/* DHKey */
uint8_t dhkey[BT_DH_KEY_LEN];
/* Remote DHKey check */
uint8_t e[16];
/* MacKey */
uint8_t mackey[16];
/* LE SC passkey */
uint32_t passkey;
/* LE SC passkey round */
uint8_t passkey_round;
/* LE SC local OOB data */
const struct bt_le_oob_sc_data *oobd_local;
/* LE SC remote OOB data */
const struct bt_le_oob_sc_data *oobd_remote;
/* Local key distribution */
uint8_t local_dist;
/* Remote key distribution */
uint8_t remote_dist;
/* The channel this context is associated with.
* This marks the beginning of the part of the structure that will not
* be memset to zero in init.
*/
struct bt_l2cap_le_chan chan;
/* Delayed work for timeout handling */
struct k_work_delayable work;
};
static unsigned int fixed_passkey = BT_PASSKEY_INVALID;
#define DISPLAY_FIXED(smp) (IS_ENABLED(CONFIG_BT_FIXED_PASSKEY) && \
fixed_passkey != BT_PASSKEY_INVALID && \
(smp)->method == PASSKEY_DISPLAY)
#if !defined(CONFIG_BT_SMP_SC_PAIR_ONLY)
/* based on table 2.8 Core Spec 2.3.5.1 Vol. 3 Part H */
static const uint8_t gen_method_legacy[5 /* remote */][5 /* local */] = {
{ JUST_WORKS, JUST_WORKS, PASSKEY_INPUT, JUST_WORKS, PASSKEY_INPUT },
{ JUST_WORKS, JUST_WORKS, PASSKEY_INPUT, JUST_WORKS, PASSKEY_INPUT },
{ PASSKEY_DISPLAY, PASSKEY_DISPLAY, PASSKEY_INPUT, JUST_WORKS,
PASSKEY_DISPLAY },
{ JUST_WORKS, JUST_WORKS, JUST_WORKS, JUST_WORKS, JUST_WORKS },
{ PASSKEY_DISPLAY, PASSKEY_DISPLAY, PASSKEY_INPUT, JUST_WORKS,
PASSKEY_ROLE },
};
#endif /* CONFIG_BT_SMP_SC_PAIR_ONLY */
#if !defined(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY)
/* based on table 2.8 Core Spec 2.3.5.1 Vol. 3 Part H */
static const uint8_t gen_method_sc[5 /* remote */][5 /* local */] = {
{ JUST_WORKS, JUST_WORKS, PASSKEY_INPUT, JUST_WORKS, PASSKEY_INPUT },
{ JUST_WORKS, PASSKEY_CONFIRM, PASSKEY_INPUT, JUST_WORKS,
PASSKEY_CONFIRM },
{ PASSKEY_DISPLAY, PASSKEY_DISPLAY, PASSKEY_INPUT, JUST_WORKS,
PASSKEY_DISPLAY },
{ JUST_WORKS, JUST_WORKS, JUST_WORKS, JUST_WORKS, JUST_WORKS },
{ PASSKEY_DISPLAY, PASSKEY_CONFIRM, PASSKEY_INPUT, JUST_WORKS,
PASSKEY_CONFIRM },
};
#endif /* !CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY */
#if defined(CONFIG_BT_BREDR)
/* SMP over BR/EDR channel specific context */
struct bt_smp_br {
/* Commands that remote is allowed to send */
ATOMIC_DEFINE(allowed_cmds, BT_SMP_NUM_CMDS);
/* Flags for SMP state machine */
ATOMIC_DEFINE(flags, SMP_NUM_FLAGS);
/* Local key distribution */
uint8_t local_dist;
/* Remote key distribution */
uint8_t remote_dist;
/* Encryption Key Size used for connection */
uint8_t enc_key_size;
/* The channel this context is associated with.
* This marks the beginning of the part of the structure that will not
* be memset to zero in init.
*/
struct bt_l2cap_br_chan chan;
/* Delayed work for timeout handling */
struct k_work_delayable work;
};
static struct bt_smp_br bt_smp_br_pool[CONFIG_BT_MAX_CONN];
#endif /* CONFIG_BT_BREDR */
static struct bt_smp bt_smp_pool[CONFIG_BT_MAX_CONN];
static bool bondable = IS_ENABLED(CONFIG_BT_BONDABLE);
static bool oobd_present;
static bool sc_supported;
static const uint8_t *sc_public_key;
static K_SEM_DEFINE(sc_local_pkey_ready, 0, 1);
static bool le_sc_supported(void)
{
/*
* If controller based ECC is to be used it must support
* "LE Read Local P-256 Public Key" and "LE Generate DH Key" commands.
* Otherwise LE SC are not supported.
*/
if (IS_ENABLED(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY)) {
return false;
}
return BT_CMD_TEST(bt_dev.supported_commands, 34, 1) &&
BT_CMD_TEST(bt_dev.supported_commands, 34, 2);
}
static uint8_t get_io_capa(void)
{
if (!bt_auth) {
goto no_callbacks;
}
/* Passkey Confirmation is valid only for LE SC */
if (bt_auth->passkey_display && bt_auth->passkey_entry &&
(bt_auth->passkey_confirm || !sc_supported)) {
return BT_SMP_IO_KEYBOARD_DISPLAY;
}
/* DisplayYesNo is useful only for LE SC */
if (sc_supported && bt_auth->passkey_display &&
bt_auth->passkey_confirm) {
return BT_SMP_IO_DISPLAY_YESNO;
}
if (bt_auth->passkey_entry) {
if (IS_ENABLED(CONFIG_BT_FIXED_PASSKEY) &&
fixed_passkey != BT_PASSKEY_INVALID) {
return BT_SMP_IO_KEYBOARD_DISPLAY;
} else {
return BT_SMP_IO_KEYBOARD_ONLY;
}
}
if (bt_auth->passkey_display) {
return BT_SMP_IO_DISPLAY_ONLY;
}
no_callbacks:
if (IS_ENABLED(CONFIG_BT_FIXED_PASSKEY) &&
fixed_passkey != BT_PASSKEY_INVALID) {
return BT_SMP_IO_DISPLAY_ONLY;
} else {
return BT_SMP_IO_NO_INPUT_OUTPUT;
}
}
#if !defined(CONFIG_BT_SMP_SC_PAIR_ONLY)
static uint8_t legacy_get_pair_method(struct bt_smp *smp, uint8_t remote_io);
#endif
static bool smp_keys_check(struct bt_conn *conn)
{
if (atomic_test_bit(conn->flags, BT_CONN_FORCE_PAIR)) {
return false;
}
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_LTK,
conn->id,
&conn->le.dst);
}
}
if (!conn->le.keys ||
!(conn->le.keys->keys & (BT_KEYS_LTK | BT_KEYS_LTK_P256))) {
return false;
}
if (conn->required_sec_level > BT_SECURITY_L2 &&
!(conn->le.keys->flags & BT_KEYS_AUTHENTICATED)) {
return false;
}
if (conn->required_sec_level > BT_SECURITY_L3 &&
!(conn->le.keys->flags & BT_KEYS_AUTHENTICATED) &&
!(conn->le.keys->keys & BT_KEYS_LTK_P256) &&
!(conn->le.keys->enc_size == BT_SMP_MAX_ENC_KEY_SIZE)) {
return false;
}
return true;
}
static uint8_t get_pair_method(struct bt_smp *smp, uint8_t remote_io)
{
#if !defined(CONFIG_BT_SMP_SC_PAIR_ONLY)
if (!atomic_test_bit(smp->flags, SMP_FLAG_SC)) {
return legacy_get_pair_method(smp, remote_io);
}
#endif
#if !defined(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY)
struct bt_smp_pairing *req, *rsp;
req = (struct bt_smp_pairing *)&smp->preq[1];
rsp = (struct bt_smp_pairing *)&smp->prsp[1];
if ((req->auth_req & rsp->auth_req) & BT_SMP_AUTH_SC) {
/* if one side has OOB data use OOB */
if ((req->oob_flag | rsp->oob_flag) & BT_SMP_OOB_DATA_MASK) {
return LE_SC_OOB;
}
}
if (remote_io > BT_SMP_IO_KEYBOARD_DISPLAY) {
return JUST_WORKS;
}
/* if none side requires MITM use JustWorks */
if (!((req->auth_req | rsp->auth_req) & BT_SMP_AUTH_MITM)) {
return JUST_WORKS;
}
return gen_method_sc[remote_io][get_io_capa()];
#else
return JUST_WORKS;
#endif
}
static enum bt_security_err security_err_get(uint8_t smp_err)
{
switch (smp_err) {
case BT_SMP_ERR_PASSKEY_ENTRY_FAILED:
case BT_SMP_ERR_DHKEY_CHECK_FAILED:
case BT_SMP_ERR_NUMERIC_COMP_FAILED:
case BT_SMP_ERR_CONFIRM_FAILED:
return BT_SECURITY_ERR_AUTH_FAIL;
case BT_SMP_ERR_OOB_NOT_AVAIL:
return BT_SECURITY_ERR_OOB_NOT_AVAILABLE;
case BT_SMP_ERR_AUTH_REQUIREMENTS:
case BT_SMP_ERR_ENC_KEY_SIZE:
return BT_SECURITY_ERR_AUTH_REQUIREMENT;
case BT_SMP_ERR_PAIRING_NOTSUPP:
case BT_SMP_ERR_CMD_NOTSUPP:
return BT_SECURITY_ERR_PAIR_NOT_SUPPORTED;
case BT_SMP_ERR_REPEATED_ATTEMPTS:
case BT_SMP_ERR_BREDR_PAIRING_IN_PROGRESS:
case BT_SMP_ERR_CROSS_TRANSP_NOT_ALLOWED:
return BT_SECURITY_ERR_PAIR_NOT_ALLOWED;
case BT_SMP_ERR_INVALID_PARAMS:
return BT_SECURITY_ERR_INVALID_PARAM;
case BT_SMP_ERR_KEY_REJECTED:
return BT_SECURITY_ERR_KEY_REJECTED;
case BT_SMP_ERR_UNSPECIFIED:
default:
return BT_SECURITY_ERR_UNSPECIFIED;
}
}
static uint8_t smp_err_get(enum bt_security_err auth_err)
{
switch (auth_err) {
case BT_SECURITY_ERR_OOB_NOT_AVAILABLE:
return BT_SMP_ERR_OOB_NOT_AVAIL;
case BT_SECURITY_ERR_AUTH_FAIL:
case BT_SECURITY_ERR_AUTH_REQUIREMENT:
return BT_SMP_ERR_AUTH_REQUIREMENTS;
case BT_SECURITY_ERR_PAIR_NOT_SUPPORTED:
return BT_SMP_ERR_PAIRING_NOTSUPP;
case BT_SECURITY_ERR_INVALID_PARAM:
return BT_SMP_ERR_INVALID_PARAMS;
case BT_SECURITY_ERR_PIN_OR_KEY_MISSING:
case BT_SECURITY_ERR_PAIR_NOT_ALLOWED:
case BT_SECURITY_ERR_UNSPECIFIED:
return BT_SMP_ERR_UNSPECIFIED;
default:
return 0;
}
}
static struct net_buf *smp_create_pdu(struct bt_smp *smp, uint8_t op, size_t len)
{
struct bt_smp_hdr *hdr;
struct net_buf *buf;
k_timeout_t timeout;
/* Don't if session had already timed out */
if (atomic_test_bit(smp->flags, SMP_FLAG_TIMEOUT)) {
timeout = K_NO_WAIT;
} else {
timeout = SMP_TIMEOUT;
}
/* Use smaller timeout if returning an error since that could be
* caused by lack of buffers.
*/
buf = bt_l2cap_create_pdu_timeout(NULL, 0, timeout);
if (!buf) {
/* If it was not possible to allocate a buffer within the
* timeout marked it as timed out.
*/
atomic_set_bit(smp->flags, SMP_FLAG_TIMEOUT);
return NULL;
}
hdr = net_buf_add(buf, sizeof(*hdr));
hdr->code = op;
return buf;
}
/* Cypher based Message Authentication Code (CMAC) with AES 128 bit
*
* Input : key ( 128-bit key )
* : in ( message to be authenticated )
* : len ( length of the message in octets )
* Output : out ( message authentication code )
*/
static int bt_smp_aes_cmac(const uint8_t *key, const uint8_t *in, size_t len,
uint8_t *out)
{
struct tc_aes_key_sched_struct sched;
struct tc_cmac_struct state;
if (tc_cmac_setup(&state, key, &sched) == TC_CRYPTO_FAIL) {
return -EIO;
}
if (tc_cmac_update(&state, in, len) == TC_CRYPTO_FAIL) {
return -EIO;
}
if (tc_cmac_final(out, &state) == TC_CRYPTO_FAIL) {
return -EIO;
}
return 0;
}
static int smp_d1(const uint8_t *key, uint16_t d, uint16_t r, uint8_t res[16])
{
int err;
BT_DBG("key %s d %u r %u", bt_hex(key, 16), d, r);
sys_put_le16(d, &res[0]);
sys_put_le16(r, &res[2]);
memset(&res[4], 0, 16 - 4);
err = bt_encrypt_le(key, res, res);
if (err) {
return err;
}
BT_DBG("res %s", bt_hex(res, 16));
return 0;
}
static int smp_f4(const uint8_t *u, const uint8_t *v, const uint8_t *x,
uint8_t z, uint8_t res[16])
{
uint8_t xs[16];
uint8_t m[65];
int err;
BT_DBG("u %s", bt_hex(u, 32));
BT_DBG("v %s", bt_hex(v, 32));
BT_DBG("x %s z 0x%x", bt_hex(x, 16), z);
/*
* U, V and Z are concatenated and used as input m to the function
* AES-CMAC and X is used as the key k.
*
* Core Spec 4.2 Vol 3 Part H 2.2.5
*
* note:
* bt_smp_aes_cmac uses BE data and smp_f4 accept LE so we swap
*/
sys_memcpy_swap(m, u, 32);
sys_memcpy_swap(m + 32, v, 32);
m[64] = z;
sys_memcpy_swap(xs, x, 16);
err = bt_smp_aes_cmac(xs, m, sizeof(m), res);
if (err) {
return err;
}
sys_mem_swap(res, 16);
BT_DBG("res %s", bt_hex(res, 16));
return err;
}
static int smp_f5(const uint8_t *w, const uint8_t *n1, const uint8_t *n2,
const bt_addr_le_t *a1, const bt_addr_le_t *a2, uint8_t *mackey,
uint8_t *ltk)
{
static const uint8_t salt[16] = { 0x6c, 0x88, 0x83, 0x91, 0xaa, 0xf5,
0xa5, 0x38, 0x60, 0x37, 0x0b, 0xdb,
0x5a, 0x60, 0x83, 0xbe };
uint8_t m[53] = { 0x00, /* counter */
0x62, 0x74, 0x6c, 0x65, /* keyID */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*n1*/
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*2*/
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a1 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a2 */
0x01, 0x00 /* length */ };
uint8_t t[16], ws[32];
int err;
BT_DBG("w %s", bt_hex(w, 32));
BT_DBG("n1 %s", bt_hex(n1, 16));
BT_DBG("n2 %s", bt_hex(n2, 16));
sys_memcpy_swap(ws, w, 32);
err = bt_smp_aes_cmac(salt, ws, 32, t);
if (err) {
return err;
}
BT_DBG("t %s", bt_hex(t, 16));
sys_memcpy_swap(m + 5, n1, 16);
sys_memcpy_swap(m + 21, n2, 16);
m[37] = a1->type;
sys_memcpy_swap(m + 38, a1->a.val, 6);
m[44] = a2->type;
sys_memcpy_swap(m + 45, a2->a.val, 6);
err = bt_smp_aes_cmac(t, m, sizeof(m), mackey);
if (err) {
return err;
}
BT_DBG("mackey %1s", bt_hex(mackey, 16));
sys_mem_swap(mackey, 16);
/* counter for ltk is 1 */
m[0] = 0x01;
err = bt_smp_aes_cmac(t, m, sizeof(m), ltk);
if (err) {
return err;
}
BT_DBG("ltk %s", bt_hex(ltk, 16));
sys_mem_swap(ltk, 16);
return 0;
}
static int smp_f6(const uint8_t *w, const uint8_t *n1, const uint8_t *n2,
const uint8_t *r, const uint8_t *iocap, const bt_addr_le_t *a1,
const bt_addr_le_t *a2, uint8_t *check)
{
uint8_t ws[16];
uint8_t m[65];
int err;
BT_DBG("w %s", bt_hex(w, 16));
BT_DBG("n1 %s", bt_hex(n1, 16));
BT_DBG("n2 %s", bt_hex(n2, 16));
BT_DBG("r %s", bt_hex(r, 16));
BT_DBG("io_cap %s", bt_hex(iocap, 3));
BT_DBG("a1 %s", bt_hex(a1, 7));
BT_DBG("a2 %s", bt_hex(a2, 7));
sys_memcpy_swap(m, n1, 16);
sys_memcpy_swap(m + 16, n2, 16);
sys_memcpy_swap(m + 32, r, 16);
sys_memcpy_swap(m + 48, iocap, 3);
m[51] = a1->type;
memcpy(m + 52, a1->a.val, 6);
sys_memcpy_swap(m + 52, a1->a.val, 6);
m[58] = a2->type;
memcpy(m + 59, a2->a.val, 6);
sys_memcpy_swap(m + 59, a2->a.val, 6);
sys_memcpy_swap(ws, w, 16);
err = bt_smp_aes_cmac(ws, m, sizeof(m), check);
if (err) {
return err;
}
BT_DBG("res %s", bt_hex(check, 16));
sys_mem_swap(check, 16);
return 0;
}
static int smp_g2(const uint8_t u[32], const uint8_t v[32],
const uint8_t x[16], const uint8_t y[16], uint32_t *passkey)
{
uint8_t m[80], xs[16];
int err;
BT_DBG("u %s", bt_hex(u, 32));
BT_DBG("v %s", bt_hex(v, 32));
BT_DBG("x %s", bt_hex(x, 16));
BT_DBG("y %s", bt_hex(y, 16));
sys_memcpy_swap(m, u, 32);
sys_memcpy_swap(m + 32, v, 32);
sys_memcpy_swap(m + 64, y, 16);
sys_memcpy_swap(xs, x, 16);
/* reuse xs (key) as buffer for result */
err = bt_smp_aes_cmac(xs, m, sizeof(m), xs);
if (err) {
return err;
}
BT_DBG("res %s", bt_hex(xs, 16));
memcpy(passkey, xs + 12, 4);
*passkey = sys_be32_to_cpu(*passkey) % 1000000;
BT_DBG("passkey %u", *passkey);
return 0;
}
static uint8_t get_encryption_key_size(struct bt_smp *smp)
{
struct bt_smp_pairing *req, *rsp;
req = (struct bt_smp_pairing *)&smp->preq[1];
rsp = (struct bt_smp_pairing *)&smp->prsp[1];
/*
* The smaller value of the initiating and responding devices maximum
* encryption key length parameters shall be used as the encryption key
* size.
*/
return MIN(req->max_key_size, rsp->max_key_size);
}
/* Check that if a new pairing procedure with an existing bond will not lower
* the established security level of the bond.
*/
static bool update_keys_check(struct bt_smp *smp, struct bt_keys *keys)
{
if (IS_ENABLED(CONFIG_BT_SMP_DISABLE_LEGACY_JW_PASSKEY) &&
!atomic_test_bit(smp->flags, SMP_FLAG_SC) &&
smp->method != LEGACY_OOB) {
return false;
}
if (IS_ENABLED(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY) &&
smp->method != LEGACY_OOB) {
return false;
}
if (!keys ||
!(keys->keys & (BT_KEYS_LTK_P256 | BT_KEYS_LTK))) {
return true;
}
if (keys->enc_size > get_encryption_key_size(smp)) {
return false;
}
if ((keys->keys & BT_KEYS_LTK_P256) &&
!atomic_test_bit(smp->flags, SMP_FLAG_SC)) {
return false;
}
if ((keys->flags & BT_KEYS_AUTHENTICATED) &&
smp->method == JUST_WORKS) {
return false;
}
if (!IS_ENABLED(CONFIG_BT_SMP_ALLOW_UNAUTH_OVERWRITE) &&
(!(keys->flags & BT_KEYS_AUTHENTICATED)
&& smp->method == JUST_WORKS)) {
return false;
}
return true;
}
static bool update_debug_keys_check(struct bt_smp *smp)
{
struct bt_conn *conn = smp->chan.chan.conn;
if (!conn->le.keys) {
conn->le.keys = bt_keys_get_addr(conn->id, &conn->le.dst);
}
if (!conn->le.keys ||
!(conn->le.keys->keys & (BT_KEYS_LTK_P256 | BT_KEYS_LTK))) {
return true;
}
if (conn->le.keys->flags & BT_KEYS_DEBUG) {
return true;
}
return false;
}
#if defined(CONFIG_BT_PRIVACY) || defined(CONFIG_BT_SIGNING) || \
!defined(CONFIG_BT_SMP_SC_PAIR_ONLY)
/* For TX callbacks */
static void smp_pairing_complete(struct bt_smp *smp, uint8_t status);
#if defined(CONFIG_BT_BREDR)
static void smp_pairing_br_complete(struct bt_smp_br *smp, uint8_t status);
#endif
static void smp_check_complete(struct bt_conn *conn, uint8_t dist_complete)
{
struct bt_l2cap_chan *chan;
if (conn->type == BT_CONN_TYPE_LE) {
struct bt_smp *smp;
chan = bt_l2cap_le_lookup_tx_cid(conn, BT_L2CAP_CID_SMP);
__ASSERT(chan, "No SMP channel found");
smp = CONTAINER_OF(chan, struct bt_smp, chan);
smp->local_dist &= ~dist_complete;
/* if all keys were distributed, pairing is done */
if (!smp->local_dist && !smp->remote_dist) {
smp_pairing_complete(smp, 0);
}
return;
}
#if defined(CONFIG_BT_BREDR)
if (conn->type == BT_CONN_TYPE_BR) {
struct bt_smp_br *smp;
chan = bt_l2cap_le_lookup_tx_cid(conn, BT_L2CAP_CID_BR_SMP);
__ASSERT(chan, "No SMP channel found");
smp = CONTAINER_OF(chan, struct bt_smp_br, chan);
smp->local_dist &= ~dist_complete;
/* if all keys were distributed, pairing is done */
if (!smp->local_dist && !smp->remote_dist) {
smp_pairing_br_complete(smp, 0);
}
}
#endif
}
#endif
#if defined(CONFIG_BT_PRIVACY)
static void smp_id_sent(struct bt_conn *conn, void *user_data)
{
smp_check_complete(conn, BT_SMP_DIST_ID_KEY);
}
#endif /* CONFIG_BT_PRIVACY */
#if defined(CONFIG_BT_SIGNING)
static void smp_sign_info_sent(struct bt_conn *conn, void *user_data)
{
smp_check_complete(conn, BT_SMP_DIST_SIGN);
}
#endif /* CONFIG_BT_SIGNING */
#if defined(CONFIG_BT_BREDR)
static int smp_h6(const uint8_t w[16], const uint8_t key_id[4], uint8_t res[16])
{
uint8_t ws[16];
uint8_t key_id_s[4];
int err;
BT_DBG("w %s", bt_hex(w, 16));
BT_DBG("key_id %s", bt_hex(key_id, 4));
sys_memcpy_swap(ws, w, 16);
sys_memcpy_swap(key_id_s, key_id, 4);
err = bt_smp_aes_cmac(ws, key_id_s, 4, res);
if (err) {
return err;
}
BT_DBG("res %s", bt_hex(res, 16));
sys_mem_swap(res, 16);
return 0;
}
static int smp_h7(const uint8_t salt[16], const uint8_t w[16], uint8_t res[16])
{
uint8_t ws[16];
uint8_t salt_s[16];
int err;
BT_DBG("w %s", bt_hex(w, 16));
BT_DBG("salt %s", bt_hex(salt, 16));
sys_memcpy_swap(ws, w, 16);
sys_memcpy_swap(salt_s, salt, 16);
err = bt_smp_aes_cmac(salt_s, ws, 16, res);
if (err) {
return err;
}
BT_DBG("res %s", bt_hex(res, 16));
sys_mem_swap(res, 16);
return 0;
}
static void sc_derive_link_key(struct bt_smp *smp)
{
/* constants as specified in Core Spec Vol.3 Part H 2.4.2.4 */
static const uint8_t lebr[4] = { 0x72, 0x62, 0x65, 0x6c };
struct bt_conn *conn = smp->chan.chan.conn;
struct bt_keys_link_key *link_key;
uint8_t ilk[16];
BT_DBG("");
/* TODO handle errors? */
/*
* At this point remote device identity is known so we can use
* destination address here
*/
link_key = bt_keys_get_link_key(&conn->le.dst.a);
if (!link_key) {
return;
}
if (atomic_test_bit(smp->flags, SMP_FLAG_CT2)) {
/* constants as specified in Core Spec Vol.3 Part H 2.4.2.4 */
static const uint8_t salt[16] = { 0x31, 0x70, 0x6d, 0x74,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };
if (smp_h7(salt, conn->le.keys->ltk.val, ilk)) {
bt_keys_link_key_clear(link_key);
return;
}
} else {
/* constants as specified in Core Spec Vol.3 Part H 2.4.2.4 */
static const uint8_t tmp1[4] = { 0x31, 0x70, 0x6d, 0x74 };
if (smp_h6(conn->le.keys->ltk.val, tmp1, ilk)) {
bt_keys_link_key_clear(link_key);
return;
}
}
if (smp_h6(ilk, lebr, link_key->val)) {
bt_keys_link_key_clear(link_key);
}
link_key->flags |= BT_LINK_KEY_SC;
if (conn->le.keys->flags & BT_KEYS_AUTHENTICATED) {
link_key->flags |= BT_LINK_KEY_AUTHENTICATED;
} else {
link_key->flags &= ~BT_LINK_KEY_AUTHENTICATED;
}
}
static void smp_br_reset(struct bt_smp_br *smp)
{
/* Clear flags first in case canceling of timeout fails. The SMP context
* shall be marked as timed out in that case.
*/
atomic_set(smp->flags, 0);
/* If canceling fails the timeout handler will set the timeout flag and
* mark the it as timed out. No new pairing procedures shall be started
* on this connection if that happens.
*/
(void)k_work_cancel_delayable(&smp->work);
atomic_set(smp->allowed_cmds, 0);
atomic_set_bit(smp->allowed_cmds, BT_SMP_CMD_PAIRING_REQ);
}
static void smp_pairing_br_complete(struct bt_smp_br *smp, uint8_t status)
{
struct bt_conn *conn = smp->chan.chan.conn;
struct bt_keys *keys;
bt_addr_le_t addr;
BT_DBG("status 0x%x", status);
/* For dualmode devices LE address is same as BR/EDR address
* and is of public type.
*/
bt_addr_copy(&addr.a, &conn->br.dst);
addr.type = BT_ADDR_LE_PUBLIC;
keys = bt_keys_find_addr(conn->id, &addr);
if (status) {
struct bt_conn_auth_info_cb *listener, *next;
if (keys) {
bt_keys_clear(keys);
}
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&bt_auth_info_cbs, listener,
next, node) {
if (listener->pairing_failed) {
listener->pairing_failed(smp->chan.chan.conn,
security_err_get(status));
}
}
} else {
bool bond_flag = atomic_test_bit(smp->flags, SMP_FLAG_BOND);
struct bt_conn_auth_info_cb *listener, *next;
if (bond_flag && keys) {
bt_keys_store(keys);
}
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&bt_auth_info_cbs, listener,
next, node) {
if (listener->pairing_complete) {
listener->pairing_complete(smp->chan.chan.conn,
bond_flag);
}
}
}
smp_br_reset(smp);
}
static void smp_br_timeout(struct k_work *work)
{
struct k_work_delayable *dwork = k_work_delayable_from_work(work);
struct bt_smp_br *smp = CONTAINER_OF(dwork, struct bt_smp_br, work);
BT_ERR("SMP Timeout");
smp_pairing_br_complete(smp, BT_SMP_ERR_UNSPECIFIED);
atomic_set_bit(smp->flags, SMP_FLAG_TIMEOUT);
}
static void smp_br_send(struct bt_smp_br *smp, struct net_buf *buf,
bt_conn_tx_cb_t cb)
{
if (bt_l2cap_send_cb(smp->chan.chan.conn, BT_L2CAP_CID_BR_SMP, buf, cb, NULL)) {
net_buf_unref(buf);
return;
}
k_work_reschedule(&smp->work, SMP_TIMEOUT);
}
static void bt_smp_br_connected(struct bt_l2cap_chan *chan)
{
struct bt_smp_br *smp = CONTAINER_OF(chan, struct bt_smp_br, chan);
BT_DBG("chan %p cid 0x%04x", chan,
CONTAINER_OF(chan, struct bt_l2cap_br_chan, chan)->tx.cid);
atomic_set_bit(smp->flags, SMP_FLAG_BR_CONNECTED);
/*
* if this flag is set it means pairing was requested before channel
* was connected
*/
if (atomic_test_bit(smp->flags, SMP_FLAG_BR_PAIR)) {
bt_smp_br_send_pairing_req(chan->conn);
}
}
static void bt_smp_br_disconnected(struct bt_l2cap_chan *chan)
{
struct bt_smp_br *smp = CONTAINER_OF(chan, struct bt_smp_br, chan);
BT_DBG("chan %p cid 0x%04x", chan,
CONTAINER_OF(chan, struct bt_l2cap_br_chan, chan)->tx.cid);
/* Channel disconnected callback is always called from a work handler
* so canceling of the timeout work should always succeed.
*/
(void)k_work_cancel_delayable(&smp->work);
(void)memset(smp, 0, sizeof(*smp));
}
static void smp_br_init(struct bt_smp_br *smp)
{
/* Initialize SMP context exluding L2CAP channel context and anything
* else declared after.
*/
(void)memset(smp, 0, offsetof(struct bt_smp_br, chan));
atomic_set_bit(smp->allowed_cmds, BT_SMP_CMD_PAIRING_FAIL);
}
static void smp_br_derive_ltk(struct bt_smp_br *smp)
{
/* constants as specified in Core Spec Vol.3 Part H 2.4.2.5 */
static const uint8_t brle[4] = { 0x65, 0x6c, 0x72, 0x62 };
struct bt_conn *conn = smp->chan.chan.conn;
struct bt_keys_link_key *link_key = conn->br.link_key;
struct bt_keys *keys;
bt_addr_le_t addr;
uint8_t ilk[16];
BT_DBG("");
if (!link_key) {
return;
}
if (IS_ENABLED(CONFIG_BT_SMP_FORCE_BREDR) && conn->encrypt != 0x02) {
BT_WARN("Using P192 Link Key for P256 LTK derivation");
}
/*
* For dualmode devices LE address is same as BR/EDR address and is of
* public type.
*/
bt_addr_copy(&addr.a, &conn->br.dst);
addr.type = BT_ADDR_LE_PUBLIC;
keys = bt_keys_get_type(BT_KEYS_LTK_P256, conn->id, &addr);
if (!keys) {
BT_ERR("Unable to get keys for %s", bt_addr_le_str(&addr));
return;
}
if (atomic_test_bit(smp->flags, SMP_FLAG_CT2)) {
/* constants as specified in Core Spec Vol.3 Part H 2.4.2.5 */
static const uint8_t salt[16] = { 0x32, 0x70, 0x6d, 0x74,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };
if (smp_h7(salt, link_key->val, ilk)) {
bt_keys_link_key_clear(link_key);
return;
}
} else {
/* constants as specified in Core Spec Vol.3 Part H 2.4.2.5 */
static const uint8_t tmp2[4] = { 0x32, 0x70, 0x6d, 0x74 };
if (smp_h6(link_key->val, tmp2, ilk)) {
bt_keys_clear(keys);
return;
}
}
if (smp_h6(ilk, brle, keys->ltk.val)) {
bt_keys_clear(keys);
return;
}
(void)memset(keys->ltk.ediv, 0, sizeof(keys->ltk.ediv));
(void)memset(keys->ltk.rand, 0, sizeof(keys->ltk.rand));
keys->enc_size = smp->enc_key_size;
if (link_key->flags & BT_LINK_KEY_AUTHENTICATED) {
keys->flags |= BT_KEYS_AUTHENTICATED;
} else {
keys->flags &= ~BT_KEYS_AUTHENTICATED;
}
BT_DBG("LTK derived from LinkKey");
}
static struct net_buf *smp_br_create_pdu(struct bt_smp_br *smp, uint8_t op,
size_t len)
{
struct bt_smp_hdr *hdr;
struct net_buf *buf;
k_timeout_t timeout;
/* Don't if session had already timed out */
if (atomic_test_bit(smp->flags, SMP_FLAG_TIMEOUT)) {
timeout = K_NO_WAIT;
} else {
timeout = SMP_TIMEOUT;
}
/* Use smaller timeout if returning an error since that could be
* caused by lack of buffers.
*/
buf = bt_l2cap_create_pdu_timeout(NULL, 0, timeout);
if (!buf) {
/* If it was not possible to allocate a buffer within the
* timeout marked it as timed out.
*/
atomic_set_bit(smp->flags, SMP_FLAG_TIMEOUT);
return NULL;
}
hdr = net_buf_add(buf, sizeof(*hdr));
hdr->code = op;
return buf;
}
static void smp_br_distribute_keys(struct bt_smp_br *smp)
{
struct bt_conn *conn = smp->chan.chan.conn;
struct bt_keys *keys;
bt_addr_le_t addr;
/*
* For dualmode devices LE address is same as BR/EDR address and is of
* public type.
*/
bt_addr_copy(&addr.a, &conn->br.dst);
addr.type = BT_ADDR_LE_PUBLIC;
keys = bt_keys_get_addr(conn->id, &addr);
if (!keys) {
BT_ERR("No keys space for %s", bt_addr_le_str(&addr));
return;
}
#if defined(CONFIG_BT_PRIVACY)
if (smp->local_dist & BT_SMP_DIST_ID_KEY) {
struct bt_smp_ident_info *id_info;
struct bt_smp_ident_addr_info *id_addr_info;
struct net_buf *buf;
smp->local_dist &= ~BT_SMP_DIST_ID_KEY;
buf = smp_br_create_pdu(smp, BT_SMP_CMD_IDENT_INFO,
sizeof(*id_info));
if (!buf) {
BT_ERR("Unable to allocate Ident Info buffer");
return;
}
id_info = net_buf_add(buf, sizeof(*id_info));
memcpy(id_info->irk, bt_dev.irk[conn->id], 16);
smp_br_send(smp, buf, NULL);
buf = smp_br_create_pdu(smp, BT_SMP_CMD_IDENT_ADDR_INFO,
sizeof(*id_addr_info));
if (!buf) {
BT_ERR("Unable to allocate Ident Addr Info buffer");
return;
}
id_addr_info = net_buf_add(buf, sizeof(*id_addr_info));
bt_addr_le_copy(&id_addr_info->addr, &bt_dev.id_addr[conn->id]);
smp_br_send(smp, buf, smp_id_sent);
}
#endif /* CONFIG_BT_PRIVACY */
#if defined(CONFIG_BT_SIGNING)
if (smp->local_dist & BT_SMP_DIST_SIGN) {
struct bt_smp_signing_info *info;
struct net_buf *buf;
smp->local_dist &= ~BT_SMP_DIST_SIGN;
buf = smp_br_create_pdu(smp, BT_SMP_CMD_SIGNING_INFO,
sizeof(*info));
if (!buf) {
BT_ERR("Unable to allocate Signing Info buffer");
return;
}
info = net_buf_add(buf, sizeof(*info));
if (bt_rand(info->csrk, sizeof(info->csrk))) {
BT_ERR("Unable to get random bytes");
return;
}
if (atomic_test_bit(smp->flags, SMP_FLAG_BOND)) {
bt_keys_add_type(keys, BT_KEYS_LOCAL_CSRK);
memcpy(keys->local_csrk.val, info->csrk, 16);
keys->local_csrk.cnt = 0U;
}
smp_br_send(smp, buf, smp_sign_info_sent);
}
#endif /* CONFIG_BT_SIGNING */
}
static bool smp_br_pairing_allowed(struct bt_smp_br *smp)
{
if (smp->chan.chan.conn->encrypt == 0x02) {
return true;
}
if (IS_ENABLED(CONFIG_BT_SMP_FORCE_BREDR) &&
smp->chan.chan.conn->encrypt == 0x01) {
BT_WARN("Allowing BR/EDR SMP with P-192 key");
return true;
}
return false;
}
static uint8_t smp_br_pairing_req(struct bt_smp_br *smp, struct net_buf *buf)
{
struct bt_smp_pairing *req = (void *)buf->data;
struct bt_conn *conn = smp->chan.chan.conn;
struct bt_smp_pairing *rsp;
struct net_buf *rsp_buf;
uint8_t max_key_size;
BT_DBG("");
/*
* If a Pairing Request is received over the BR/EDR transport when
* either cross-transport key derivation/generation is not supported or
* the BR/EDR transport is not encrypted using a Link Key generated
* using P256, a Pairing Failed shall be sent with the error code
* "Cross-transport Key Derivation/Generation not allowed" (0x0E)."
*/
if (!smp_br_pairing_allowed(smp)) {
return BT_SMP_ERR_CROSS_TRANSP_NOT_ALLOWED;
}
max_key_size = bt_conn_enc_key_size(conn);
if (!max_key_size) {
BT_DBG("Invalid encryption key size");
return BT_SMP_ERR_UNSPECIFIED;
}
if (req->max_key_size != max_key_size) {
return BT_SMP_ERR_ENC_KEY_SIZE;
}
rsp_buf = smp_br_create_pdu(smp, BT_SMP_CMD_PAIRING_RSP, sizeof(*rsp));
if (!rsp_buf) {
return BT_SMP_ERR_UNSPECIFIED;
}
smp_br_init(smp);
smp->enc_key_size = max_key_size;
/*
* If Secure Connections pairing has been initiated over BR/EDR, the IO
* Capability, OOB data flag and Auth Req fields of the SM Pairing
* Request/Response PDU shall be set to zero on transmission, and
* ignored on reception.
*/
rsp = net_buf_add(rsp_buf, sizeof(*rsp));
rsp->auth_req = 0x00;
rsp->io_capability = 0x00;
rsp->oob_flag = 0x00;
rsp->max_key_size = max_key_size;
rsp->init_key_dist = (req->init_key_dist & BR_RECV_KEYS_SC);
rsp->resp_key_dist = (req->resp_key_dist & BR_RECV_KEYS_SC);
smp->local_dist = rsp->resp_key_dist;
smp->remote_dist = rsp->init_key_dist;
smp_br_send(smp, rsp_buf, NULL);
atomic_set_bit(smp->flags, SMP_FLAG_PAIRING);
/* derive LTK if requested and clear distribution bits */
if ((smp->local_dist & BT_SMP_DIST_ENC_KEY) &&
(smp->remote_dist & BT_SMP_DIST_ENC_KEY)) {
smp_br_derive_ltk(smp);
}
smp->local_dist &= ~BT_SMP_DIST_ENC_KEY;
smp->remote_dist &= ~BT_SMP_DIST_ENC_KEY;
/* BR/EDR acceptor is like LE Peripheral and distributes keys first */
smp_br_distribute_keys(smp);
if (smp->remote_dist & BT_SMP_DIST_ID_KEY) {
atomic_set_bit(smp->allowed_cmds, BT_SMP_CMD_IDENT_INFO);
} else if (smp->remote_dist & BT_SMP_DIST_SIGN) {
atomic_set_bit(smp->allowed_cmds, BT_SMP_CMD_SIGNING_INFO);
}
/* if all keys were distributed, pairing is done */
if (!smp->local_dist && !smp->remote_dist) {
smp_pairing_br_complete(smp, 0);
}
return 0;
}
static uint8_t smp_br_pairing_rsp(struct bt_smp_br *smp, struct net_buf *buf)
{
struct bt_smp_pairing *rsp = (void *)buf->data;
struct bt_conn *conn = smp->chan.chan.conn;
uint8_t max_key_size;
BT_DBG("");
max_key_size = bt_conn_enc_key_size(conn);
if (!max_key_size) {
BT_DBG("Invalid encryption key size");
return BT_SMP_ERR_UNSPECIFIED;
}
if (rsp->max_key_size != max_key_size) {
return BT_SMP_ERR_ENC_KEY_SIZE;
}
smp->local_dist &= rsp->init_key_dist;
smp->remote_dist &= rsp->resp_key_dist;
smp->local_dist &= SEND_KEYS_SC;
smp->remote_dist &= RECV_KEYS_SC;
/* Peripheral distributes its keys first */
if (smp->remote_dist & BT_SMP_DIST_ID_KEY) {
atomic_set_bit(smp->allowed_cmds, BT_SMP_CMD_IDENT_INFO);
} else if (smp->remote_dist & BT_SMP_DIST_SIGN) {
atomic_set_bit(smp->allowed_cmds, BT_SMP_CMD_SIGNING_INFO);
}
/* derive LTK if requested and clear distribution bits */
if ((smp->local_dist & BT_SMP_DIST_ENC_KEY) &&
(smp->remote_dist & BT_SMP_DIST_ENC_KEY)) {
smp_br_derive_ltk(smp);
}
smp->local_dist &= ~BT_SMP_DIST_ENC_KEY;
smp->remote_dist &= ~BT_SMP_DIST_ENC_KEY;
/* Pairing acceptor distributes it's keys first */
if (smp->remote_dist) {
return 0;
}
smp_br_distribute_keys(smp);
/* if all keys were distributed, pairing is done */
if (!smp->local_dist && !smp->remote_dist) {
smp_pairing_br_complete(smp, 0);
}
return 0;
}
static uint8_t smp_br_pairing_failed(struct bt_smp_br *smp, struct net_buf *buf)
{
struct bt_smp_pairing_fail *req = (void *)buf->data;
BT_ERR("reason 0x%x", req->reason);
smp_pairing_br_complete(smp, req->reason);
smp_br_reset(smp);
/* return no error to avoid sending Pairing Failed in response */
return 0;
}
static uint8_t smp_br_ident_info(struct bt_smp_br *smp, struct net_buf *buf)
{
struct bt_smp_ident_info *req = (void *)buf->data;
struct bt_conn *conn = smp->chan.chan.conn;
struct bt_keys *keys;
bt_addr_le_t addr;
BT_DBG("");
/* TODO should we resolve LE address if matching RPA is connected? */
/*
* For dualmode devices LE address is same as BR/EDR address and is of
* public type.
*/
bt_addr_copy(&addr.a, &conn->br.dst);
addr.type = BT_ADDR_LE_PUBLIC;
keys = bt_keys_get_type(BT_KEYS_IRK, conn->id, &addr);
if (!keys) {
BT_ERR("Unable to get keys for %s", bt_addr_le_str(&addr));
return BT_SMP_ERR_UNSPECIFIED;
}
memcpy(keys->irk.val, req->irk, sizeof(keys->irk.val));
atomic_set_bit(smp->allowed_cmds, BT_SMP_CMD_IDENT_ADDR_INFO);
return 0;
}
static uint8_t smp_br_ident_addr_info(struct bt_smp_br *smp,
struct net_buf *buf)
{
struct bt_conn *conn = smp->chan.chan.conn;
struct bt_smp_ident_addr_info *req = (void *)buf->data;
bt_addr_le_t addr;
BT_DBG("identity %s", bt_addr_le_str(&req->addr));
/*
* For dual mode device identity address must be same as BR/EDR address
* and be of public type. So if received one doesn't match BR/EDR
* address we fail.
*/
bt_addr_copy(&addr.a, &conn->br.dst);
addr.type = BT_ADDR_LE_PUBLIC;
if (bt_addr_le_cmp(&addr, &req->addr)) {
return BT_SMP_ERR_UNSPECIFIED;
}
smp->remote_dist &= ~BT_SMP_DIST_ID_KEY;
if (smp->remote_dist & BT_SMP_DIST_SIGN) {
atomic_set_bit(smp->allowed_cmds, BT_SMP_CMD_SIGNING_INFO);
}
if (conn->role == BT_CONN_ROLE_CENTRAL && !smp->remote_dist) {
smp_br_distribute_keys(smp);
}
/* if all keys were distributed, pairing is done */
if (!smp->local_dist && !smp->remote_dist) {
smp_pairing_br_complete(smp, 0);
}
return 0;
}
#if defined(CONFIG_BT_SIGNING)
static uint8_t smp_br_signing_info(struct bt_smp_br *smp, struct net_buf *buf)
{
struct bt_smp_signing_info *req = (void *)buf->data;
struct bt_conn *conn = smp->chan.chan.conn;
struct bt_keys *keys;
bt_addr_le_t addr;
BT_DBG("");
/*
* For dualmode devices LE address is same as BR/EDR address and is of
* public type.
*/
bt_addr_copy(&addr.a, &conn->br.dst);
addr.type = BT_ADDR_LE_PUBLIC;
keys = bt_keys_get_type(BT_KEYS_REMOTE_CSRK, conn->id, &addr);
if (!keys) {
BT_ERR("Unable to get keys for %s", bt_addr_le_str(&addr));
return BT_SMP_ERR_UNSPECIFIED;
}
memcpy(keys->remote_csrk.val, req->csrk, sizeof(keys->remote_csrk.val));
smp->remote_dist &= ~BT_SMP_DIST_SIGN;
if (conn->role == BT_CONN_ROLE_CENTRAL && !smp->remote_dist) {
smp_br_distribute_keys(smp);
}
/* if all keys were distributed, pairing is done */
if (!smp->local_dist && !smp->remote_dist) {
smp_pairing_br_complete(smp, 0);
}
return 0;
}
#else
static uint8_t smp_br_signing_info(struct bt_smp_br *smp, struct net_buf *buf)
{
return BT_SMP_ERR_CMD_NOTSUPP;
}
#endif /* CONFIG_BT_SIGNING */
static const struct {
uint8_t (*func)(struct bt_smp_br *smp, struct net_buf *buf);
uint8_t expect_len;
} br_handlers[] = {
{ }, /* No op-code defined for 0x00 */
{ smp_br_pairing_req, sizeof(struct bt_smp_pairing) },
{ smp_br_pairing_rsp, sizeof(struct bt_smp_pairing) },
{ }, /* pairing confirm not used over BR/EDR */
{ }, /* pairing random not used over BR/EDR */
{ smp_br_pairing_failed, sizeof(struct bt_smp_pairing_fail) },
{ }, /* encrypt info not used over BR/EDR */
{ }, /* central ident not used over BR/EDR */
{ smp_br_ident_info, sizeof(struct bt_smp_ident_info) },
{ smp_br_ident_addr_info, sizeof(struct bt_smp_ident_addr_info) },
{ smp_br_signing_info, sizeof(struct bt_smp_signing_info) },
/* security request not used over BR/EDR */
/* public key not used over BR/EDR */
/* DHKey check not used over BR/EDR */
};
static int smp_br_error(struct bt_smp_br *smp, uint8_t reason)
{
struct bt_smp_pairing_fail *rsp;
struct net_buf *buf;
/* reset context and report */
smp_br_reset(smp);
buf = smp_br_create_pdu(smp, BT_SMP_CMD_PAIRING_FAIL, sizeof(*rsp));
if (!buf) {
return -ENOBUFS;
}
rsp = net_buf_add(buf, sizeof(*rsp));
rsp->reason = reason;
/*
* SMP timer is not restarted for PairingFailed so don't use
* smp_br_send
*/
if (bt_l2cap_send(smp->chan.chan.conn, BT_L2CAP_CID_SMP, buf)) {
net_buf_unref(buf);
}
return 0;
}
static int bt_smp_br_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
{
struct bt_smp_br *smp = CONTAINER_OF(chan, struct bt_smp_br, chan);
struct bt_smp_hdr *hdr;
uint8_t err;
if (buf->len < sizeof(*hdr)) {
BT_ERR("Too small SMP PDU received");
return 0;
}
hdr = net_buf_pull_mem(buf, sizeof(*hdr));
BT_DBG("Received SMP code 0x%02x len %u", hdr->code, buf->len);
/*
* If SMP timeout occurred "no further SMP commands shall be sent over
* the L2CAP Security Manager Channel. A new SM procedure shall only be
* performed when a new physical link has been established."
*/
if (atomic_test_bit(smp->flags, SMP_FLAG_TIMEOUT)) {
BT_WARN("SMP command (code 0x%02x) received after timeout",
hdr->code);
return 0;
}
if (hdr->code >= ARRAY_SIZE(br_handlers) ||
!br_handlers[hdr->code].func) {
BT_WARN("Unhandled SMP code 0x%02x", hdr->code);
smp_br_error(smp, BT_SMP_ERR_CMD_NOTSUPP);
return 0;
}
if (!atomic_test_and_clear_bit(smp->allowed_cmds, hdr->code)) {
BT_WARN("Unexpected SMP code 0x%02x", hdr->code);
smp_br_error(smp, BT_SMP_ERR_UNSPECIFIED);
return 0;
}
if (buf->len != br_handlers[hdr->code].expect_len) {
BT_ERR("Invalid len %u for code 0x%02x", buf->len, hdr->code);
smp_br_error(smp, BT_SMP_ERR_INVALID_PARAMS);
return 0;
}
err = br_handlers[hdr->code].func(smp, buf);
if (err) {
smp_br_error(smp, err);
}
return 0;
}
static bool br_sc_supported(void)
{
if (IS_ENABLED(CONFIG_BT_SMP_FORCE_BREDR)) {
BT_WARN("Enabling BR/EDR SMP without BR/EDR SC support");
return true;
}
return BT_FEAT_SC(bt_dev.features);
}
static int bt_smp_br_accept(struct bt_conn *conn, struct bt_l2cap_chan **chan)
{
static const struct bt_l2cap_chan_ops ops = {
.connected = bt_smp_br_connected,
.disconnected = bt_smp_br_disconnected,
.recv = bt_smp_br_recv,
};
int i;
/* Check BR/EDR SC is supported */
if (!br_sc_supported()) {
return -ENOTSUP;
}
BT_DBG("conn %p handle %u", conn, conn->handle);
for (i = 0; i < ARRAY_SIZE(bt_smp_pool); i++) {
struct bt_smp_br *smp = &bt_smp_br_pool[i];
if (smp->chan.chan.conn) {
continue;
}
smp->chan.chan.ops = &ops;
*chan = &smp->chan.chan;
k_work_init_delayable(&smp->work, smp_br_timeout);
smp_br_reset(smp);
return 0;
}
BT_ERR("No available SMP context for conn %p", conn);
return -ENOMEM;
}
static struct bt_smp_br *smp_br_chan_get(struct bt_conn *conn)
{
struct bt_l2cap_chan *chan;
chan = bt_l2cap_br_lookup_rx_cid(conn, BT_L2CAP_CID_BR_SMP);
if (!chan) {
BT_ERR("Unable to find SMP channel");
return NULL;
}
return CONTAINER_OF(chan, struct bt_smp_br, chan);
}
int bt_smp_br_send_pairing_req(struct bt_conn *conn)
{
struct bt_smp_pairing *req;
struct net_buf *req_buf;
uint8_t max_key_size;
struct bt_smp_br *smp;
smp = smp_br_chan_get(conn);
if (!smp) {
return -ENOTCONN;
}
/* SMP Timeout */
if (atomic_test_bit(smp->flags, SMP_FLAG_TIMEOUT)) {
return -EIO;
}
/* pairing is in progress */
if (atomic_test_bit(smp->flags, SMP_FLAG_PAIRING)) {
return -EBUSY;
}
/* check if we are allowed to start SMP over BR/EDR */
if (!smp_br_pairing_allowed(smp)) {
return 0;
}
/* Channel not yet connected, will start pairing once connected */
if (!atomic_test_bit(smp->flags, SMP_FLAG_BR_CONNECTED)) {
atomic_set_bit(smp->flags, SMP_FLAG_BR_PAIR);
return 0;
}
max_key_size = bt_conn_enc_key_size(conn);
if (!max_key_size) {
BT_DBG("Invalid encryption key size");
return -EIO;
}
smp_br_init(smp);
smp->enc_key_size = max_key_size;
req_buf = smp_br_create_pdu(smp, BT_SMP_CMD_PAIRING_REQ, sizeof(*req));
if (!req_buf) {
return -ENOBUFS;
}
req = net_buf_add(req_buf, sizeof(*req));
/*
* If Secure Connections pairing has been initiated over BR/EDR, the IO
* Capability, OOB data flag and Auth Req fields of the SM Pairing
* Request/Response PDU shall be set to zero on transmission, and
* ignored on reception.
*/
req->auth_req = 0x00;
req->io_capability = 0x00;
req->oob_flag = 0x00;
req->max_key_size = max_key_size;
req->init_key_dist = BR_SEND_KEYS_SC;
req->resp_key_dist = BR_RECV_KEYS_SC;
smp_br_send(smp, req_buf, NULL);
smp->local_dist = BR_SEND_KEYS_SC;
smp->remote_dist = BR_RECV_KEYS_SC;
atomic_set_bit(smp->allowed_cmds, BT_SMP_CMD_PAIRING_RSP);
atomic_set_bit(smp->flags, SMP_FLAG_PAIRING);
return 0;
}
#endif /* CONFIG_BT_BREDR */
static void smp_reset(struct bt_smp *smp)
{
struct bt_conn *conn = smp->chan.chan.conn;
/* Clear flags first in case canceling of timeout fails. The SMP context
* shall be marked as timed out in that case.
*/
atomic_set(smp->flags, 0);
/* If canceling fails the timeout handler will set the timeout flag and
* mark the it as timed out. No new pairing procedures shall be started
* on this connection if that happens.
*/
(void)k_work_cancel_delayable(&smp->work);
smp->method = JUST_WORKS;
atomic_set(smp->allowed_cmds, 0);
if (IS_ENABLED(CONFIG_BT_CENTRAL) &&
conn->role == BT_HCI_ROLE_CENTRAL) {
atomic_set_bit(smp->allowed_cmds, BT_SMP_CMD_SECURITY_REQUEST);
return;
}
if (IS_ENABLED(CONFIG_BT_PERIPHERAL)) {
atomic_set_bit(smp->allowed_cmds, BT_SMP_CMD_PAIRING_REQ);
}
}
static uint8_t hci_err_get(enum bt_security_err err)
{
switch (err) {
case BT_SECURITY_ERR_SUCCESS:
return BT_HCI_ERR_SUCCESS;
case BT_SECURITY_ERR_AUTH_FAIL:
return BT_HCI_ERR_AUTH_FAIL;
case BT_SECURITY_ERR_PIN_OR_KEY_MISSING:
return BT_HCI_ERR_PIN_OR_KEY_MISSING;
case BT_SECURITY_ERR_PAIR_NOT_SUPPORTED:
return BT_HCI_ERR_PAIRING_NOT_SUPPORTED;
case BT_SECURITY_ERR_PAIR_NOT_ALLOWED:
return BT_HCI_ERR_PAIRING_NOT_ALLOWED;
case BT_SECURITY_ERR_INVALID_PARAM:
return BT_HCI_ERR_INVALID_PARAM;
default:
return BT_HCI_ERR_UNSPECIFIED;
}
}
/* Note: This function not only does set the status but also calls smp_reset
* at the end which clears any flags previously set.
*/
static void smp_pairing_complete(struct bt_smp *smp, uint8_t status)
{
struct bt_conn *conn = smp->chan.chan.conn;
BT_DBG("status 0x%x", status);
if (!status) {
#if defined(CONFIG_BT_BREDR)
/*
* Don't derive if Debug Keys are used.
* TODO should we allow this if BR/EDR is already connected?
*/
if (atomic_test_bit(smp->flags, SMP_FLAG_DERIVE_LK) &&
(!atomic_test_bit(smp->flags, SMP_FLAG_SC_DEBUG_KEY) ||
IS_ENABLED(CONFIG_BT_STORE_DEBUG_KEYS))) {
sc_derive_link_key(smp);
}
#endif /* CONFIG_BT_BREDR */
bool bond_flag = atomic_test_bit(smp->flags, SMP_FLAG_BOND);
struct bt_conn_auth_info_cb *listener, *next;
if (IS_ENABLED(CONFIG_BT_LOG_SNIFFER_INFO)) {
bt_keys_show_sniffer_info(conn->le.keys, NULL);
}
if (bond_flag) {
bt_keys_store(conn->le.keys);
}
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&bt_auth_info_cbs, listener,
next, node) {
if (listener->pairing_complete) {
listener->pairing_complete(conn, bond_flag);
}
}
} else {
enum bt_security_err security_err = security_err_get(status);
/* Clear the key pool entry in case of pairing failure if the
* keys already existed before the pairing procedure or the
* pairing failed during key distribution.
*/
if (conn->le.keys &&
(!conn->le.keys->enc_size ||
atomic_test_bit(smp->flags, SMP_FLAG_KEYS_DISTR))) {
bt_keys_clear(conn->le.keys);
conn->le.keys = NULL;
}
if (!atomic_test_bit(smp->flags, SMP_FLAG_KEYS_DISTR)) {
bt_conn_security_changed(conn,
hci_err_get(security_err),
security_err);
}
/* Check SMP_FLAG_PAIRING as bt_conn_security_changed may
* have called the pairing_failed callback already.
*/
if (atomic_test_bit(smp->flags, SMP_FLAG_PAIRING)) {
struct bt_conn_auth_info_cb *listener, *next;
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&bt_auth_info_cbs,
listener, next,
node) {
if (listener->pairing_failed) {
listener->pairing_failed(conn, security_err);
}
}
}
}
smp_reset(smp);
if (conn->sec_level != conn->required_sec_level) {
bt_smp_start_security(conn);
}
}
static void smp_timeout(struct k_work *work)
{
struct bt_smp *smp = CONTAINER_OF(work, struct bt_smp, work);
BT_ERR("SMP Timeout");
smp_pairing_complete(smp, BT_SMP_ERR_UNSPECIFIED);
/* smp_pairing_complete clears flags so setting timeout flag must come
* after it.
*/
atomic_set_bit(smp->flags, SMP_FLAG_TIMEOUT);
}
static void smp_send(struct bt_smp *smp, struct net_buf *buf,
bt_conn_tx_cb_t cb, void *user_data)
{
if (bt_l2cap_send_cb(smp->chan.chan.conn, BT_L2CAP_CID_SMP, buf, cb, NULL)) {
net_buf_unref(buf);
return;
}
k_work_reschedule(&smp->work, SMP_TIMEOUT);
}
static int smp_error(struct bt_smp *smp, uint8_t reason)
{
struct bt_smp_pairing_fail *rsp;
struct net_buf *buf;
if (atomic_test_bit(smp