diff --git a/doc/zephyr.doxyfile.in b/doc/zephyr.doxyfile.in index 0b3400b1308..1df6817274c 100644 --- a/doc/zephyr.doxyfile.in +++ b/doc/zephyr.doxyfile.in @@ -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" \ diff --git a/include/bluetooth/conn.h b/include/bluetooth/conn.h index ad81a19ee9a..a199f44e04b 100644 --- a/include/bluetooth/conn.h +++ b/include/bluetooth/conn.h @@ -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 diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index a8a355aa6e1..663f21e476d 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -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 diff --git a/subsys/bluetooth/host/smp.c b/subsys/bluetooth/host/smp.c index 9fd82c879f9..884cea45e36 100644 --- a/subsys/bluetooth/host/smp.c +++ b/subsys/bluetooth/host/smp.c @@ -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) {