Bluetooth: Add support for fixed passkeys
Add a new bt_passkey_set() API that can be used to set a fixed passkey to be used for pairing. The new API also requires a new Kconfig option to be enabled first (CONFIG_BT_FIXED_PASSKEY). Fixes #8350 Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
parent
ef70fc85a9
commit
c446c8267b
4 changed files with 113 additions and 44 deletions
|
@ -382,6 +382,28 @@ struct bt_conn_cb {
|
||||||
*/
|
*/
|
||||||
void bt_conn_cb_register(struct bt_conn_cb *cb);
|
void bt_conn_cb_register(struct bt_conn_cb *cb);
|
||||||
|
|
||||||
|
/** @def BT_PASSKEY_INVALID
|
||||||
|
*
|
||||||
|
* Special passkey value that can be used to disable a previously
|
||||||
|
* set fixed passkey.
|
||||||
|
*/
|
||||||
|
#define BT_PASSKEY_INVALID 0xffffffff
|
||||||
|
|
||||||
|
/** @brief Set a fixed passkey to be used for pairing.
|
||||||
|
*
|
||||||
|
* This API is only available when the CONFIG_BT_FIXED_PASSKEY
|
||||||
|
* configuration option has been enabled.
|
||||||
|
*
|
||||||
|
* Sets a fixed passkey to be used for pairing. If set, the
|
||||||
|
* pairing_confim() callback will be called for all incoming pairings.
|
||||||
|
*
|
||||||
|
* @param passkey A valid passkey (0 - 999999) or BT_PASSKEY_INVALID
|
||||||
|
* to disable a previously set fixed passkey.
|
||||||
|
*
|
||||||
|
* @return 0 on success or a negative error code on failure.
|
||||||
|
*/
|
||||||
|
int bt_passkey_set(unsigned int passkey);
|
||||||
|
|
||||||
/** Authenticated pairing callback structure */
|
/** Authenticated pairing callback structure */
|
||||||
struct bt_conn_auth_cb {
|
struct bt_conn_auth_cb {
|
||||||
/** @brief Display a passkey to the user.
|
/** @brief Display a passkey to the user.
|
||||||
|
|
|
@ -281,6 +281,13 @@ config BT_SMP_SC_ONLY
|
||||||
Security Mode 1 Level 4 stands for authenticated LE Secure Connections
|
Security Mode 1 Level 4 stands for authenticated LE Secure Connections
|
||||||
pairing with encryption. Enabling this option disables legacy pairing.
|
pairing with encryption. Enabling this option disables legacy pairing.
|
||||||
|
|
||||||
|
config BT_FIXED_PASSKEY
|
||||||
|
bool "Use a fixed passkey for pairing"
|
||||||
|
help
|
||||||
|
With this option enabled, the application will be able to call the
|
||||||
|
bt_passkey_set() API to set a fixed passkey. If set, the
|
||||||
|
pairing_confim() callback will be called for all incoming pairings.
|
||||||
|
|
||||||
config BT_USE_DEBUG_KEYS
|
config BT_USE_DEBUG_KEYS
|
||||||
bool "Enable Security Manager Debug Mode"
|
bool "Enable Security Manager Debug Mode"
|
||||||
depends on BT_TINYCRYPT_ECC
|
depends on BT_TINYCRYPT_ECC
|
||||||
|
|
|
@ -1967,7 +1967,6 @@ int bt_conn_auth_cb_register(const struct bt_conn_auth_cb *cb)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bt_auth = cb;
|
bt_auth = cb;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,6 +174,12 @@ struct bt_smp {
|
||||||
struct k_delayed_work work;
|
struct k_delayed_work 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_ONLY)
|
#if !defined(CONFIG_BT_SMP_SC_ONLY)
|
||||||
/* based on table 2.8 Core Spec 2.3.5.1 Vol. 3 Part H */
|
/* based on table 2.8 Core Spec 2.3.5.1 Vol. 3 Part H */
|
||||||
static const u8_t gen_method_legacy[5 /* remote */][5 /* local */] = {
|
static const u8_t gen_method_legacy[5 /* remote */][5 /* local */] = {
|
||||||
|
@ -244,7 +250,7 @@ static u8_t sc_public_key[64];
|
||||||
static u8_t get_io_capa(void)
|
static u8_t get_io_capa(void)
|
||||||
{
|
{
|
||||||
if (!bt_auth) {
|
if (!bt_auth) {
|
||||||
return BT_SMP_IO_NO_INPUT_OUTPUT;
|
goto no_callbacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Passkey Confirmation is valid only for LE SC */
|
/* Passkey Confirmation is valid only for LE SC */
|
||||||
|
@ -260,14 +266,25 @@ static u8_t get_io_capa(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bt_auth->passkey_entry) {
|
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;
|
return BT_SMP_IO_KEYBOARD_ONLY;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (bt_auth->passkey_display) {
|
if (bt_auth->passkey_display) {
|
||||||
return BT_SMP_IO_DISPLAY_ONLY;
|
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;
|
return BT_SMP_IO_NO_INPUT_OUTPUT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8_t get_pair_method(struct bt_smp *smp, u8_t remote_io)
|
static u8_t get_pair_method(struct bt_smp *smp, u8_t remote_io)
|
||||||
|
@ -1916,16 +1933,23 @@ static u8_t legacy_request_tk(struct bt_smp *smp)
|
||||||
|
|
||||||
switch (smp->method) {
|
switch (smp->method) {
|
||||||
case PASSKEY_DISPLAY:
|
case PASSKEY_DISPLAY:
|
||||||
|
if (IS_ENABLED(CONFIG_BT_FIXED_PASSKEY) &&
|
||||||
|
fixed_passkey != BT_PASSKEY_INVALID) {
|
||||||
|
passkey = fixed_passkey;
|
||||||
|
} else {
|
||||||
if (bt_rand(&passkey, sizeof(passkey))) {
|
if (bt_rand(&passkey, sizeof(passkey))) {
|
||||||
return BT_SMP_ERR_UNSPECIFIED;
|
return BT_SMP_ERR_UNSPECIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
passkey %= 1000000;
|
passkey %= 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bt_auth && bt_auth->passkey_display) {
|
||||||
|
atomic_set_bit(smp->flags, SMP_FLAG_DISPLAY);
|
||||||
bt_auth->passkey_display(conn, passkey);
|
bt_auth->passkey_display(conn, passkey);
|
||||||
|
}
|
||||||
|
|
||||||
passkey = sys_cpu_to_le32(passkey);
|
sys_put_le32(passkey, smp->tk);
|
||||||
memcpy(smp->tk, &passkey, sizeof(passkey));
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case PASSKEY_INPUT:
|
case PASSKEY_INPUT:
|
||||||
|
@ -1978,7 +2002,7 @@ static u8_t legacy_pairing_req(struct bt_smp *smp, u8_t remote_io)
|
||||||
smp->method = legacy_get_pair_method(smp, remote_io);
|
smp->method = legacy_get_pair_method(smp, remote_io);
|
||||||
|
|
||||||
/* ask for consent if pairing is not due to sending SecReq*/
|
/* ask for consent if pairing is not due to sending SecReq*/
|
||||||
if (smp->method == JUST_WORKS &&
|
if ((DISPLAY_FIXED(smp) || smp->method == JUST_WORKS) &&
|
||||||
!atomic_test_bit(smp->flags, SMP_FLAG_SEC_REQ) &&
|
!atomic_test_bit(smp->flags, SMP_FLAG_SEC_REQ) &&
|
||||||
bt_auth && bt_auth->pairing_confirm) {
|
bt_auth && bt_auth->pairing_confirm) {
|
||||||
atomic_set_bit(smp->flags, SMP_FLAG_USER);
|
atomic_set_bit(smp->flags, SMP_FLAG_USER);
|
||||||
|
@ -2184,7 +2208,7 @@ static u8_t legacy_pairing_rsp(struct bt_smp *smp, u8_t remote_io)
|
||||||
smp->method = legacy_get_pair_method(smp, remote_io);
|
smp->method = legacy_get_pair_method(smp, remote_io);
|
||||||
|
|
||||||
/* ask for consent if this is due to received SecReq */
|
/* ask for consent if this is due to received SecReq */
|
||||||
if (smp->method == JUST_WORKS &&
|
if ((DISPLAY_FIXED(smp) || smp->method == JUST_WORKS) &&
|
||||||
atomic_test_bit(smp->flags, SMP_FLAG_SEC_REQ) &&
|
atomic_test_bit(smp->flags, SMP_FLAG_SEC_REQ) &&
|
||||||
bt_auth && bt_auth->pairing_confirm) {
|
bt_auth && bt_auth->pairing_confirm) {
|
||||||
atomic_set_bit(smp->flags, SMP_FLAG_USER);
|
atomic_set_bit(smp->flags, SMP_FLAG_USER);
|
||||||
|
@ -2404,24 +2428,17 @@ static u8_t smp_pairing_req(struct bt_smp *smp, struct net_buf *buf)
|
||||||
|
|
||||||
smp->method = get_pair_method(smp, req->io_capability);
|
smp->method = get_pair_method(smp, req->io_capability);
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_SMP_SC_ONLY) &&
|
if (IS_ENABLED(CONFIG_BT_SMP_SC_ONLY) && smp->method == JUST_WORKS) {
|
||||||
smp->method == JUST_WORKS) {
|
|
||||||
return BT_SMP_ERR_AUTH_REQUIREMENTS;
|
return BT_SMP_ERR_AUTH_REQUIREMENTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (smp->method == JUST_WORKS) {
|
if ((DISPLAY_FIXED(smp) || smp->method == JUST_WORKS) &&
|
||||||
if (IS_ENABLED(CONFIG_BT_SMP_SC_ONLY)) {
|
!atomic_test_bit(smp->flags, SMP_FLAG_SEC_REQ) &&
|
||||||
return BT_SMP_ERR_AUTH_REQUIREMENTS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ask for consent if pairing is not due to sending SecReq*/
|
|
||||||
if (!atomic_test_bit(smp->flags, SMP_FLAG_SEC_REQ) &&
|
|
||||||
bt_auth && bt_auth->pairing_confirm) {
|
bt_auth && bt_auth->pairing_confirm) {
|
||||||
atomic_set_bit(smp->flags, SMP_FLAG_USER);
|
atomic_set_bit(smp->flags, SMP_FLAG_USER);
|
||||||
bt_auth->pairing_confirm(smp->chan.chan.conn);
|
bt_auth->pairing_confirm(smp->chan.chan.conn);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PUBLIC_KEY);
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PUBLIC_KEY);
|
||||||
return send_pairing_rsp(smp);
|
return send_pairing_rsp(smp);
|
||||||
|
@ -2564,22 +2581,20 @@ static u8_t smp_pairing_rsp(struct bt_smp *smp, struct net_buf *buf)
|
||||||
|
|
||||||
smp->method = get_pair_method(smp, rsp->io_capability);
|
smp->method = get_pair_method(smp, rsp->io_capability);
|
||||||
|
|
||||||
smp->local_dist &= SEND_KEYS_SC;
|
if (IS_ENABLED(CONFIG_BT_SMP_SC_ONLY) && smp->method == JUST_WORKS) {
|
||||||
smp->remote_dist &= RECV_KEYS_SC;
|
|
||||||
|
|
||||||
if (smp->method == JUST_WORKS) {
|
|
||||||
if (IS_ENABLED(CONFIG_BT_SMP_SC_ONLY)) {
|
|
||||||
return BT_SMP_ERR_AUTH_REQUIREMENTS;
|
return BT_SMP_ERR_AUTH_REQUIREMENTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ask for consent if this is due to received SecReq */
|
smp->local_dist &= SEND_KEYS_SC;
|
||||||
if (atomic_test_bit(smp->flags, SMP_FLAG_SEC_REQ) &&
|
smp->remote_dist &= RECV_KEYS_SC;
|
||||||
|
|
||||||
|
if ((DISPLAY_FIXED(smp) || smp->method == JUST_WORKS) &&
|
||||||
|
atomic_test_bit(smp->flags, SMP_FLAG_SEC_REQ) &&
|
||||||
bt_auth && bt_auth->pairing_confirm) {
|
bt_auth && bt_auth->pairing_confirm) {
|
||||||
atomic_set_bit(smp->flags, SMP_FLAG_USER);
|
atomic_set_bit(smp->flags, SMP_FLAG_USER);
|
||||||
bt_auth->pairing_confirm(smp->chan.chan.conn);
|
bt_auth->pairing_confirm(smp->chan.chan.conn);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!sc_local_pkey_valid) {
|
if (!sc_local_pkey_valid) {
|
||||||
atomic_set_bit(smp->flags, SMP_FLAG_PKEY_SEND);
|
atomic_set_bit(smp->flags, SMP_FLAG_PKEY_SEND);
|
||||||
|
@ -3233,15 +3248,24 @@ static u8_t generate_dhkey(struct bt_smp *smp)
|
||||||
|
|
||||||
static u8_t display_passkey(struct bt_smp *smp)
|
static u8_t display_passkey(struct bt_smp *smp)
|
||||||
{
|
{
|
||||||
|
if (IS_ENABLED(CONFIG_BT_FIXED_PASSKEY) &&
|
||||||
|
fixed_passkey != BT_PASSKEY_INVALID) {
|
||||||
|
smp->passkey = fixed_passkey;
|
||||||
|
} else {
|
||||||
if (bt_rand(&smp->passkey, sizeof(smp->passkey))) {
|
if (bt_rand(&smp->passkey, sizeof(smp->passkey))) {
|
||||||
return BT_SMP_ERR_UNSPECIFIED;
|
return BT_SMP_ERR_UNSPECIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
smp->passkey %= 1000000;
|
smp->passkey %= 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
smp->passkey_round = 0;
|
smp->passkey_round = 0;
|
||||||
|
|
||||||
|
if (bt_auth && bt_auth->passkey_display) {
|
||||||
atomic_set_bit(smp->flags, SMP_FLAG_DISPLAY);
|
atomic_set_bit(smp->flags, SMP_FLAG_DISPLAY);
|
||||||
bt_auth->passkey_display(smp->chan.chan.conn, smp->passkey);
|
bt_auth->passkey_display(smp->chan.chan.conn, smp->passkey);
|
||||||
|
}
|
||||||
|
|
||||||
smp->passkey = sys_cpu_to_le32(smp->passkey);
|
smp->passkey = sys_cpu_to_le32(smp->passkey);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -4353,6 +4377,23 @@ int bt_smp_auth_pairing_confirm(struct bt_conn *conn)
|
||||||
}
|
}
|
||||||
#endif /* !CONFIG_BT_SMP_SC_ONLY */
|
#endif /* !CONFIG_BT_SMP_SC_ONLY */
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_FIXED_PASSKEY)
|
||||||
|
int bt_passkey_set(unsigned int passkey)
|
||||||
|
{
|
||||||
|
if (passkey == BT_PASSKEY_INVALID) {
|
||||||
|
passkey = BT_PASSKEY_INVALID;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (passkey > 999999) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fixed_passkey = passkey;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_SMP_FIXED_PASSKEY */
|
||||||
|
|
||||||
void bt_smp_update_keys(struct bt_conn *conn)
|
void bt_smp_update_keys(struct bt_conn *conn)
|
||||||
{
|
{
|
||||||
struct bt_smp *smp;
|
struct bt_smp *smp;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue