Bluetooth: Host: Add generic pairing query callback

Similar to pairing_confirm this callback is called each
time a peer requests pairing, but for all types of
pairings, except SSP. The pairing req/rsp information is
passed as a parameter so the application can decide
wheter to accept or reject the pairing.

Fixes: #21036

Signed-off-by: Martin Rieva <mrrv@demant.com>
This commit is contained in:
Martin Rieva 2020-01-23 11:45:20 +01:00 committed by Johan Hedberg
parent 34346c41ac
commit 2685a94c02
4 changed files with 160 additions and 0 deletions

View file

@ -1966,6 +1966,7 @@ PREDEFINED = "CONFIG_ARCH_HAS_CUSTOM_BUSY_WAIT" \
"CONFIG_BT_MESH_MODEL_EXTENSIONS" \
"CONFIG_BT_REMOTE_INFO" \
"CONFIG_BT_SMP" \
"CONFIG_BT_SMP_APP_PAIRING_ACCEPT" \
"CONFIG_DEVICE_POWER_MANAGEMENT" \
"CONFIG_ERRNO" \
"CONFIG_EXECUTION_BENCHMARKING" \

View file

@ -711,8 +711,72 @@ struct bt_conn_oob_info {
};
};
#if defined(CONFIG_BT_SMP_APP_PAIRING_ACCEPT)
/** @brief Pairing request and pairing response info structure.
*
* This structure is the same for both smp_pairing_req and smp_pairing_rsp
* and a subset of the packet data, except for the initial Code octet.
* It is documented in Core Spec. Vol. 3, Part H, 3.5.1 and 3.5.2.
*/
struct bt_conn_pairing_feat {
/** IO Capability, Core Spec. Vol 3, Part H, 3.5.1, Table 3.4 */
u8_t io_capability;
/** OOB data flag, Core Spec. Vol 3, Part H, 3.5.1, Table 3.5 */
u8_t oob_data_flag;
/** AuthReq, Core Spec. Vol 3, Part H, 3.5.1, Fig. 3.3 */
u8_t auth_req;
/** Maximum Encryption Key Size, Core Spec. Vol 3, Part H, 3.5.1 */
u8_t max_enc_key_size;
/** Initiator Key Distribution/Generation, Core Spec. Vol 3, Part H,
* 3.6.1, Fig. 3.11
*/
u8_t init_key_dist;
/** Responder Key Distribution/Generation, Core Spec. Vol 3, Part H
* 3.6.1, Fig. 3.11
*/
u8_t resp_key_dist;
};
#endif /* CONFIG_BT_SMP_APP_PAIRING_ACCEPT */
/** Authenticated pairing callback structure */
struct bt_conn_auth_cb {
#if defined(CONFIG_BT_SMP_APP_PAIRING_ACCEPT)
/** @brief Query to proceed incoming pairing or not.
*
* On any incoming pairing req/rsp this callback will be called for
* the application to decide whether to allow for the pairing to
* continue.
*
* The pairing info received from the peer is passed to assist
* making the decision.
*
* As this callback is synchronous the application should return
* a response value immediately. Otherwise it may affect the
* timing during pairing. Hence, this information should not be
* conveyed to the user to take action.
*
* The remaining callbacks are not affected by this, but do notice
* that other callbacks can be called during the pairing. Eg. if
* pairing_confirm is registered both will be called for Just-Works
* pairings.
*
* This callback may be unregistered in which case pairing continues
* as if the Kconfig flag was not set.
*
* This callback is not called for BR/EDR Secure Simple Pairing (SSP).
*
* @param conn Connection where pairing is initiated.
* @param feat Pairing req/resp info.
*/
enum bt_security_err (*pairing_accept)(struct bt_conn *conn,
const struct bt_conn_pairing_feat *const feat);
#endif /* CONFIG_BT_SMP_APP_PAIRING_ACCEPT */
/** @brief Display a passkey to the user.
*
* When called the application is expected to display the given

View file

@ -320,6 +320,16 @@ config BT_SIGNING
This option enables data signing which is used for transferring
authenticated data in an unencrypted connection.
config BT_SMP_APP_PAIRING_ACCEPT
bool "Accept or reject pairing initiative"
help
When receiving pairing request or pairing response query the
application whether to accept to proceed with pairing or not. This is
for pairing over SMP and does not affect SSP, which will continue
pairing without querying the application.
The application can return an error code, which is translated into
a SMP return value if the pairing is not allowed.
config BT_SMP_SC_PAIR_ONLY
bool "Disable legacy pairing"
help

View file

@ -404,6 +404,33 @@ static enum bt_security_err auth_err_get(u8_t smp_err)
}
}
#if defined(CONFIG_BT_SMP_APP_PAIRING_ACCEPT)
static u8_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;
}
}
#endif /* CONFIG_BT_SMP_APP_PAIRING_ACCEPT */
static struct net_buf *smp_create_pdu(struct bt_smp *smp, u8_t op, size_t len)
{
struct bt_smp_hdr *hdr;
@ -2110,6 +2137,26 @@ static u8_t send_pairing_rsp(struct bt_smp *smp)
}
#endif /* CONFIG_BT_PERIPHERAL */
static u8_t smp_pairing_accept_query(struct bt_conn *conn,
struct bt_smp_pairing *pairing)
{
#if defined(CONFIG_BT_SMP_APP_PAIRING_ACCEPT)
if (bt_auth && bt_auth->pairing_accept) {
const struct bt_conn_pairing_feat feat = {
.io_capability = pairing->io_capability,
.oob_data_flag = pairing->oob_flag,
.auth_req = pairing->auth_req,
.max_enc_key_size = pairing->max_key_size,
.init_key_dist = pairing->init_key_dist,
.resp_key_dist = pairing->resp_key_dist
};
return smp_err_get(bt_auth->pairing_accept(conn, &feat));
}
#endif /* CONFIG_BT_SMP_APP_PAIRING_ACCEPT */
return 0;
}
#if !defined(CONFIG_BT_SMP_SC_PAIR_ONLY)
static int smp_s1(const u8_t k[16], const u8_t r1[16],
const u8_t r2[16], u8_t out[16])
@ -2809,6 +2856,16 @@ static u8_t smp_pairing_req(struct bt_smp *smp, struct net_buf *buf)
#if defined(CONFIG_BT_SMP_SC_PAIR_ONLY)
return BT_SMP_ERR_AUTH_REQUIREMENTS;
#else
if (IS_ENABLED(CONFIG_BT_SMP_APP_PAIRING_ACCEPT)) {
u8_t err;
err = smp_pairing_accept_query(smp->chan.chan.conn,
req);
if (err) {
return err;
}
}
return legacy_pairing_req(smp);
#endif /* CONFIG_BT_SMP_SC_PAIR_ONLY */
}
@ -2825,6 +2882,15 @@ static u8_t smp_pairing_req(struct bt_smp *smp, struct net_buf *buf)
return BT_SMP_ERR_ENC_KEY_SIZE;
}
if (IS_ENABLED(CONFIG_BT_SMP_APP_PAIRING_ACCEPT)) {
u8_t err;
err = smp_pairing_accept_query(smp->chan.chan.conn, req);
if (err) {
return err;
}
}
if ((DISPLAY_FIXED(smp) || smp->method == JUST_WORKS) &&
!atomic_test_bit(smp->flags, SMP_FLAG_SEC_REQ) &&
bt_auth && bt_auth->pairing_confirm) {
@ -2991,6 +3057,16 @@ static u8_t smp_pairing_rsp(struct bt_smp *smp, struct net_buf *buf)
#if defined(CONFIG_BT_SMP_SC_PAIR_ONLY)
return BT_SMP_ERR_AUTH_REQUIREMENTS;
#else
if (IS_ENABLED(CONFIG_BT_SMP_APP_PAIRING_ACCEPT)) {
u8_t err;
err = smp_pairing_accept_query(smp->chan.chan.conn,
rsp);
if (err) {
return err;
}
}
return legacy_pairing_rsp(smp);
#endif /* CONFIG_BT_SMP_SC_PAIR_ONLY */
}
@ -3010,6 +3086,15 @@ static u8_t smp_pairing_rsp(struct bt_smp *smp, struct net_buf *buf)
smp->local_dist &= SEND_KEYS_SC;
smp->remote_dist &= RECV_KEYS_SC;
if (IS_ENABLED(CONFIG_BT_SMP_APP_PAIRING_ACCEPT)) {
u8_t err;
err = smp_pairing_accept_query(smp->chan.chan.conn, rsp);
if (err) {
return err;
}
}
if ((DISPLAY_FIXED(smp) || smp->method == JUST_WORKS) &&
atomic_test_bit(smp->flags, SMP_FLAG_SEC_REQ) &&
bt_auth && bt_auth->pairing_confirm) {