Bluetooth: Add support for confirming incoming JustWorks pairing

If incoming pairing request would result in JustWorks pairing this
can be used to request consent from user for accepting it.

Change-Id: If0695d0e1bb010bade6a16abe1b57a2ce07856cc
Signed-off-by: Szymon Janc <ext.szymon.janc@tieto.com>
This commit is contained in:
Szymon Janc 2016-02-08 10:53:03 +01:00 committed by Johan Hedberg
commit c2a1ac8ae7
5 changed files with 153 additions and 13 deletions

View file

@ -354,6 +354,11 @@ int bt_conn_auth_passkey_confirm(struct bt_conn *conn)
return -ENOSYS; return -ENOSYS;
} }
int bt_conn_auth_pairing_confirm(struct bt_conn *conn)
{
return -ENOSYS;
}
/* Connection related events */ /* Connection related events */
static void notify_connected(struct bt_conn *conn) static void notify_connected(struct bt_conn *conn)

View file

@ -315,6 +315,7 @@ struct bt_conn_auth_cb {
void (*passkey_entry)(struct bt_conn *conn); void (*passkey_entry)(struct bt_conn *conn);
void (*passkey_confirm)(struct bt_conn *conn, unsigned int passkey); void (*passkey_confirm)(struct bt_conn *conn, unsigned int passkey);
void (*cancel)(struct bt_conn *conn); void (*cancel)(struct bt_conn *conn);
void (*pairing_confirm)(struct bt_conn *conn);
#if defined(CONFIG_BLUETOOTH_BREDR) #if defined(CONFIG_BLUETOOTH_BREDR)
void (*pincode_entry)(struct bt_conn *conn, bool highsec); void (*pincode_entry)(struct bt_conn *conn, bool highsec);
#endif #endif
@ -364,6 +365,17 @@ int bt_conn_auth_cancel(struct bt_conn *conn);
*/ */
int bt_conn_auth_passkey_confirm(struct bt_conn *conn); int bt_conn_auth_passkey_confirm(struct bt_conn *conn);
/** @brief Reply if incoming pairing was confirmed by user.
*
* This function should be called only after pairing_confirm callback from
* bt_conn_auth_cb structure was called if user confirmed incoming pairing.
*
* @param conn Connection object.
*
* @return Zero on success or negative error code otherwise
*/
int bt_conn_auth_pairing_confirm(struct bt_conn *conn);
#if defined(CONFIG_BLUETOOTH_BREDR) #if defined(CONFIG_BLUETOOTH_BREDR)
/** @brief Reply with entered PIN code. /** @brief Reply with entered PIN code.
* *

View file

@ -434,9 +434,6 @@ void bt_conn_ssp_auth(struct bt_conn *conn, uint32_t passkey)
return; return;
} }
/* TODO: As pairing acceptor call user pairing consent API callback. */
/* Start interactive authentication if valid, default to justworks. */
switch (conn->br.pairing_method) { switch (conn->br.pairing_method) {
case PASSKEY_CONFIRM: case PASSKEY_CONFIRM:
atomic_set_bit(conn->flags, BT_CONN_USER); atomic_set_bit(conn->flags, BT_CONN_USER);
@ -450,9 +447,17 @@ void bt_conn_ssp_auth(struct bt_conn *conn, uint32_t passkey)
atomic_set_bit(conn->flags, BT_CONN_USER); atomic_set_bit(conn->flags, BT_CONN_USER);
bt_auth->passkey_entry(conn); bt_auth->passkey_entry(conn);
break; break;
default: case JUST_WORKS:
/* TODO do this only for incoming pairing */
if (bt_auth && bt_auth->pairing_confirm) {
atomic_set_bit(conn->flags, BT_CONN_USER);
bt_auth->pairing_confirm(conn);
break;
}
ssp_confirm_reply(conn); ssp_confirm_reply(conn);
break; break;
default:
break;
} }
} }
@ -1528,6 +1533,26 @@ int bt_conn_auth_cancel(struct bt_conn *conn)
return -EINVAL; return -EINVAL;
} }
int bt_conn_auth_pairing_confirm(struct bt_conn *conn)
{
if (!bt_auth) {
return -EINVAL;
}
switch (conn->type) {
#if defined(CONFIG_BLUETOOTH_SMP)
case BT_CONN_TYPE_LE:
return bt_smp_auth_pairing_confirm(conn);
#endif /* CONFIG_BLUETOOTH_SMP */
#if defined(CONFIG_BLUETOOTH_BREDR)
case BT_CONN_TYPE_BR:
return ssp_confirm_reply(conn);
#endif /* CONFIG_BLUETOOTH_BREDR */
default:
return -EINVAL;
}
}
#endif /* CONFIG_BLUETOOTH_SMP || CONFIG_BLUETOOTH_BREDR */ #endif /* CONFIG_BLUETOOTH_SMP || CONFIG_BLUETOOTH_BREDR */
static void background_scan_init(void) static void background_scan_init(void)

View file

@ -94,6 +94,7 @@ enum {
SMP_FLAG_USER, /* if waiting for user input */ SMP_FLAG_USER, /* if waiting for user input */
SMP_FLAG_BOND, /* if bonding */ SMP_FLAG_BOND, /* if bonding */
SMP_FLAG_SC_DEBUG_KEY, /* if Secure Connection are using debug key */ SMP_FLAG_SC_DEBUG_KEY, /* if Secure Connection are using debug key */
SMP_FLAG_SEC_REQ, /* if Security Request was sent/received */
}; };
/* SMP channel specific context */ /* SMP channel specific context */
@ -1112,13 +1113,22 @@ static uint8_t legacy_pairing_req(struct bt_smp *smp, uint8_t remote_io)
BT_DBG(""); BT_DBG("");
smp->method = legacy_get_pair_method(smp, remote_io);
/* ask for consent if pairing is not due to sending SecReq*/
if (smp->method == JUST_WORKS &&
!atomic_test_bit(&smp->flags, SMP_FLAG_SEC_REQ) &&
bt_auth && bt_auth->pairing_confirm) {
atomic_set_bit(&smp->flags, SMP_FLAG_USER);
bt_auth->pairing_confirm(smp->chan.conn);
return 0;
}
ret = send_pairing_rsp(smp); ret = send_pairing_rsp(smp);
if (ret) { if (ret) {
return ret; return ret;
} }
smp->method = legacy_get_pair_method(smp, remote_io);
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PAIRING_CONFIRM); atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PAIRING_CONFIRM);
return legacy_request_tk(smp); return legacy_request_tk(smp);
@ -1310,6 +1320,15 @@ static uint8_t legacy_pairing_rsp(struct bt_smp *smp, uint8_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 */
if (smp->method == JUST_WORKS &&
atomic_test_bit(&smp->flags, SMP_FLAG_SEC_REQ) &&
bt_auth && bt_auth->pairing_confirm) {
atomic_set_bit(&smp->flags, SMP_FLAG_USER);
bt_auth->pairing_confirm(smp->chan.conn);
return 0;
}
ret = legacy_request_tk(smp); ret = legacy_request_tk(smp);
if (ret) { if (ret) {
return ret; return ret;
@ -1482,7 +1501,6 @@ static uint8_t smp_pairing_req(struct bt_smp *smp, struct net_buf *buf)
if ((rsp->auth_req & BT_SMP_AUTH_SC) && if ((rsp->auth_req & BT_SMP_AUTH_SC) &&
(req->auth_req & BT_SMP_AUTH_SC)) { (req->auth_req & BT_SMP_AUTH_SC)) {
atomic_set_bit(&smp->flags, SMP_FLAG_SC); atomic_set_bit(&smp->flags, SMP_FLAG_SC);
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PUBLIC_KEY);
rsp->init_key_dist &= RECV_KEYS_SC; rsp->init_key_dist &= RECV_KEYS_SC;
rsp->resp_key_dist &= SEND_KEYS_SC; rsp->resp_key_dist &= SEND_KEYS_SC;
@ -1514,6 +1532,21 @@ static uint8_t smp_pairing_req(struct bt_smp *smp, struct net_buf *buf)
} }
#endif/* CONFIG_BLUETOOTH_SMP_SC_ONLY */ #endif/* CONFIG_BLUETOOTH_SMP_SC_ONLY */
if (smp->method == JUST_WORKS) {
#if defined(CONFIG_BLUETOOTH_SMP_SC_ONLY)
return BT_SMP_ERR_AUTH_REQUIREMENTS;
#else
/* 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) {
atomic_set_bit(&smp->flags, SMP_FLAG_USER);
bt_auth->pairing_confirm(smp->chan.conn);
return 0;
}
#endif/* CONFIG_BLUETOOTH_SMP_SC_ONLY */
}
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PUBLIC_KEY);
return send_pairing_rsp(smp); return send_pairing_rsp(smp);
} }
#else #else
@ -1649,15 +1682,23 @@ static uint8_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);
#if defined(CONFIG_BLUETOOTH_SMP_SC_ONLY)
if (smp->method == JUST_WORKS) {
return BT_SMP_ERR_AUTH_REQUIREMENTS;
}
#endif/* CONFIG_BLUETOOTH_SMP_SC_ONLY */
smp->local_dist &= SEND_KEYS_SC; smp->local_dist &= SEND_KEYS_SC;
smp->remote_dist &= RECV_KEYS_SC; smp->remote_dist &= RECV_KEYS_SC;
if (smp->method == JUST_WORKS) {
#if defined(CONFIG_BLUETOOTH_SMP_SC_ONLY)
return BT_SMP_ERR_AUTH_REQUIREMENTS;
#else
/* ask for consent if this is due to received SecReq */
if (atomic_test_bit(&smp->flags, SMP_FLAG_SEC_REQ) &&
bt_auth && bt_auth->pairing_confirm) {
atomic_set_bit(&smp->flags, SMP_FLAG_USER);
bt_auth->pairing_confirm(smp->chan.conn);
return 0;
}
#endif/* CONFIG_BLUETOOTH_SMP_SC_ONLY */
}
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);
return 0; return 0;
@ -2278,6 +2319,8 @@ pair:
return BT_SMP_ERR_UNSPECIFIED; return BT_SMP_ERR_UNSPECIFIED;
} }
atomic_set_bit(&smp->flags, SMP_FLAG_SEC_REQ);
return 0; return 0;
} }
#else #else
@ -3340,11 +3383,65 @@ int bt_smp_auth_cancel(struct bt_conn *conn)
case PASSKEY_CONFIRM: case PASSKEY_CONFIRM:
return smp_error(smp, BT_SMP_ERR_CONFIRM_FAILED); return smp_error(smp, BT_SMP_ERR_CONFIRM_FAILED);
case JUST_WORKS: case JUST_WORKS:
return smp_error(smp, BT_SMP_ERR_UNSPECIFIED);
default: default:
return 0; return 0;
} }
} }
#if !defined(CONFIG_BLUETOOTH_SMP_SC_ONLY)
int bt_smp_auth_pairing_confirm(struct bt_conn *conn)
{
struct bt_smp *smp;
smp = smp_chan_get(conn);
if (!smp) {
return -EINVAL;
}
if (!atomic_test_and_clear_bit(&smp->flags, SMP_FLAG_USER)) {
return -EINVAL;
}
#if defined(CONFIG_BLUETOOTH_CENTRAL)
if (conn->role == BT_CONN_ROLE_MASTER) {
if (!atomic_test_bit(&smp->flags, SMP_FLAG_SC)) {
atomic_set_bit(&smp->allowed_cmds,
BT_SMP_CMD_PAIRING_CONFIRM);
return legacy_send_pairing_confirm(smp);
}
if (!sc_local_pkey_valid) {
atomic_set_bit(&smp->flags, SMP_FLAG_PKEY_SEND);
return 0;
}
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PUBLIC_KEY);
return sc_send_public_key(smp);
}
#endif /* CONFIG_BLUETOOTH_CENTRAL */
#if defined(CONFIG_BLUETOOTH_PERIPHERAL)
if (!atomic_test_bit(&smp->flags, SMP_FLAG_SC)) {
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PAIRING_CONFIRM);
return send_pairing_rsp(smp);
}
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PUBLIC_KEY);
if (send_pairing_rsp(smp)) {
return -EIO;
}
#endif /* CONFIG_BLUETOOTH_PERIPHERAL */
return 0;
}
#else
int bt_smp_auth_pairing_confirm(struct bt_conn *conn)
{
/* confirm_pairing will never be called in LE SC only mode */
return -EINVAL;
}
#endif /* !CONFIG_BLUETOOTH_SMP_SC_ONLY */
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;

View file

@ -144,6 +144,7 @@ int bt_smp_init(void);
int bt_smp_auth_passkey_entry(struct bt_conn *conn, unsigned int passkey); int bt_smp_auth_passkey_entry(struct bt_conn *conn, unsigned int passkey);
int bt_smp_auth_passkey_confirm(struct bt_conn *conn); int bt_smp_auth_passkey_confirm(struct bt_conn *conn);
int bt_smp_auth_pairing_confirm(struct bt_conn *conn);
int bt_smp_auth_cancel(struct bt_conn *conn); int bt_smp_auth_cancel(struct bt_conn *conn);
/** brief Verify signed message /** brief Verify signed message