diff --git a/nimble/host/include/host/ble_gap.h b/nimble/host/include/host/ble_gap.h index 5aa1fab76..b21899ed8 100644 --- a/nimble/host/include/host/ble_gap.h +++ b/nimble/host/include/host/ble_gap.h @@ -417,6 +417,7 @@ struct ble_gap_passkey_params { * - BLE_SM_IOACT_INPUT * - BLE_SM_IOACT_DISP * - BLE_SM_IOACT_NUMCMP + * - BLE_SM_IOACT_STATIC */ uint8_t action; diff --git a/nimble/host/include/host/ble_hs.h b/nimble/host/include/host/ble_hs.h index 79718b40c..adc2efd8d 100644 --- a/nimble/host/include/host/ble_hs.h +++ b/nimble/host/include/host/ble_hs.h @@ -358,6 +358,22 @@ struct ble_hs_cfg { /** @brief Weather to use GATT caching or not for discovery operations */ uint8_t gatt_use_cache; +#if MYNEWT_VAL(STATIC_PASSKEY) + /** @brief Security Manager Static Passkey flag + * + * If set, the device will use a static passkey for pairing instead of + * generating dynamic passkeys. + */ + unsigned sm_static_passkey:1; + + /** @brief Security Manager Static Passkey Value + * + * The static passkey value to use when sm_static_passkey is enabled. + * Must be a 6-digit number (0-999999). + */ + uint32_t sm_static_passkey_val; +#endif + /** @brief Stack reset callback * * This callback is executed when the host resets itself and the controller diff --git a/nimble/host/include/host/ble_sm.h b/nimble/host/include/host/ble_sm.h index ff381cf25..8cdb85ca9 100644 --- a/nimble/host/include/host/ble_sm.h +++ b/nimble/host/include/host/ble_sm.h @@ -22,6 +22,9 @@ #include #include "syscfg/syscfg.h" +#if MYNEWT_VAL(STATIC_PASSKEY) +#include +#endif #ifdef __cplusplus extern "C" { @@ -87,7 +90,8 @@ extern "C" { #define BLE_SM_IOACT_DISP 3 #define BLE_SM_IOACT_NUMCMP 4 #define BLE_SM_IOACT_OOB_SC 5 -#define BLE_SM_IOACT_MAX_PLUS_ONE 6 +#define BLE_SM_IOACT_STATIC 6 +#define BLE_SM_IOACT_MAX_PLUS_ONE 7 struct ble_sm_sc_oob_data { /** Random Number. */ @@ -114,9 +118,42 @@ int ble_sm_sc_oob_generate_data(struct ble_sm_sc_oob_data *oob_data); #if NIMBLE_BLE_SM int ble_sm_inject_io(uint16_t conn_handle, struct ble_sm_io *pkey); + +#if MYNEWT_VAL(STATIC_PASSKEY) +/** + * @brief Configure static passkey for BLE pairing + * + * This function enables static passkey mode and sets the passkey value. + * When enabled, the device will automatically use the specified passkey + * for both display and input actions during pairing, eliminating the + * need for dynamic passkey generation. + * + * @param passkey The 6-digit static passkey (0-999999) + * @param enable Whether to enable (true) or disable (false) static passkey + * + * @return 0 on success, error code on failure + */ +int ble_sm_configure_static_passkey(uint32_t passkey, bool enable); + +/** + * @brief Get the current static passkey configuration + * + * @param passkey Pointer to store the current static passkey value + * @param enabled Pointer to store whether static passkey is enabled + * + * @return 0 on success, error code on failure + */ +int ble_sm_get_static_passkey_config(uint32_t *passkey, bool *enabled); +#endif #else #define ble_sm_inject_io(conn_handle, pkey) \ ((void)(conn_handle), BLE_HS_ENOTSUP) +#if !MYNEWT_VAL(STATIC_PASSKEY) +#define ble_sm_configure_static_passkey(passkey, enable) \ + ((void)(passkey), (void)(enable), BLE_HS_ENOTSUP) +#define ble_sm_get_static_passkey_config(passkey, enabled) \ + ((void)(passkey), (void)(enabled), BLE_HS_ENOTSUP) +#endif #endif #ifdef __cplusplus diff --git a/nimble/host/src/ble_gap.c b/nimble/host/src/ble_gap.c index 9a4c4f83d..b865c122b 100644 --- a/nimble/host/src/ble_gap.c +++ b/nimble/host/src/ble_gap.c @@ -8848,6 +8848,23 @@ ble_gap_passkey_event(uint16_t conn_handle, BLE_HS_LOG(DEBUG, "send passkey action request %d\n", passkey_params->action); +#if MYNEWT_VAL(STATIC_PASSKEY) + /* Check if static passkey is configured and handle automatically */ + if (ble_hs_cfg.sm_static_passkey) { + struct ble_sm_io pk; + int rc; + + if (passkey_params->action == BLE_SM_IOACT_STATIC) { + pk.action = BLE_SM_IOACT_STATIC; + pk.passkey = ble_hs_cfg.sm_static_passkey_val; + rc = ble_sm_inject_io(conn_handle, &pk); + if (rc == 0) { + BLE_HS_LOG(INFO, "static passkey injected"); + return; + } + } + } +#endif memset(&event, 0, sizeof event); event.type = BLE_GAP_EVENT_PASSKEY_ACTION; diff --git a/nimble/host/src/ble_sm.c b/nimble/host/src/ble_sm.c index 2e434662d..20ad8bbb3 100644 --- a/nimble/host/src/ble_sm.c +++ b/nimble/host/src/ble_sm.c @@ -806,6 +806,11 @@ ble_sm_ioact_state(uint8_t action) case BLE_SM_IOACT_DISP: return BLE_SM_PROC_STATE_CONFIRM; +#if MYNEWT_VAL(STATIC_PASSKEY) + case BLE_SM_IOACT_STATIC: + return BLE_SM_PROC_STATE_CONFIRM; +#endif + default: BLE_HS_DBG_ASSERT(0); return BLE_SM_PROC_STATE_NONE; @@ -3056,7 +3061,26 @@ ble_sm_inject_io(uint16_t conn_handle, struct ble_sm_io *pkey) } break; #endif +#if MYNEWT_VAL(STATIC_PASSKEY) + case BLE_SM_IOACT_STATIC: + if (pkey->passkey > 999999) { + rc = BLE_HS_EINVAL; + } else { + proc->flags |= BLE_SM_PROC_F_IO_INJECTED; + memset(proc->tk, 0, 16); + proc->tk[0] = (pkey->passkey >> 0) & 0xff; + proc->tk[1] = (pkey->passkey >> 8) & 0xff; + proc->tk[2] = (pkey->passkey >> 16) & 0xff; + proc->tk[3] = (pkey->passkey >> 24) & 0xff; + if ((proc->flags & BLE_SM_PROC_F_INITIATOR) || + (proc->flags & BLE_SM_PROC_F_ADVANCE_ON_IO)) + { + res.execute = 1; + } + } + break; +#endif default: BLE_HS_DBG_ASSERT(0); rc = BLE_HS_EINVAL; @@ -3160,4 +3184,40 @@ ble_sm_create_chan(uint16_t conn_handle) return chan; } +#if MYNEWT_VAL(STATIC_PASSKEY) +int +ble_sm_configure_static_passkey(uint32_t passkey, bool enable) +{ + if (enable) { + /* Validate passkey is 6 digits */ + if (passkey > 999999) { + return BLE_HS_EINVAL; + } + /* Passkey authentication requires MITM; ensure it is enabled. */ + ble_hs_cfg.sm_mitm = 1; + ble_hs_cfg.sm_static_passkey = 1; + ble_hs_cfg.sm_static_passkey_val = passkey; + BLE_HS_LOG(DEBUG, "static passkey enabled\n"); + } else { + ble_hs_cfg.sm_static_passkey = 0; + ble_hs_cfg.sm_static_passkey_val = 0; + BLE_HS_LOG(INFO, "static passkey disabled\n"); + } + + return 0; +} + +int +ble_sm_get_static_passkey_config(uint32_t *passkey, bool *enabled) +{ + if (passkey == NULL || enabled == NULL) { + return BLE_HS_EINVAL; + } + + *enabled = ble_hs_cfg.sm_static_passkey; + *passkey = ble_hs_cfg.sm_static_passkey_val; + + return 0; +} +#endif #endif diff --git a/nimble/host/src/ble_sm_lgcy.c b/nimble/host/src/ble_sm_lgcy.c index 1a500fb74..050b86b89 100644 --- a/nimble/host/src/ble_sm_lgcy.c +++ b/nimble/host/src/ble_sm_lgcy.c @@ -68,6 +68,17 @@ ble_sm_lgcy_io_action(struct ble_sm_proc *proc, uint8_t *action) pair_req = (struct ble_sm_pair_cmd *) &proc->pair_req[1]; pair_rsp = (struct ble_sm_pair_cmd *) &proc->pair_rsp[1]; +#if MYNEWT_VAL(STATIC_PASSKEY) + /* Check if static passkey is enabled - if so, use static passkey action */ + if (ble_hs_cfg.sm_static_passkey) + { + *action = BLE_SM_IOACT_STATIC; + proc->pair_alg = BLE_SM_PAIR_ALG_PASSKEY; + proc->flags |= BLE_SM_PROC_F_AUTHENTICATED; + return 0; + } +#endif + if (pair_req->oob_data_flag == BLE_SM_PAIR_OOB_YES && pair_rsp->oob_data_flag == BLE_SM_PAIR_OOB_YES) { *action = BLE_SM_IOACT_OOB; @@ -100,6 +111,13 @@ ble_sm_lgcy_io_action(struct ble_sm_proc *proc, uint8_t *action) proc->flags |= BLE_SM_PROC_F_AUTHENTICATED; break; +#if MYNEWT_VAL(STATIC_PASSKEY) + case BLE_SM_IOACT_STATIC: + proc->pair_alg = BLE_SM_PAIR_ALG_PASSKEY; + proc->flags |= BLE_SM_PROC_F_AUTHENTICATED; + break; +#endif + default: BLE_HS_DBG_ASSERT(0); return BLE_HS_EINVAL; diff --git a/nimble/host/src/ble_sm_sc.c b/nimble/host/src/ble_sm_sc.c index 10634db9b..faf3191c3 100644 --- a/nimble/host/src/ble_sm_sc.c +++ b/nimble/host/src/ble_sm_sc.c @@ -105,6 +105,17 @@ ble_sm_sc_io_action(struct ble_sm_proc *proc, uint8_t *action) pair_req = (struct ble_sm_pair_cmd *) &proc->pair_req[1]; pair_rsp = (struct ble_sm_pair_cmd *) &proc->pair_rsp[1]; +#if MYNEWT_VAL(STATIC_PASSKEY) + /* Check if static passkey is enabled - if so, use static passkey action */ + if (ble_hs_cfg.sm_static_passkey) + { + *action = BLE_SM_IOACT_STATIC; + proc->pair_alg = BLE_SM_PAIR_ALG_PASSKEY; + proc->flags |= BLE_SM_PROC_F_AUTHENTICATED; + return 0; + } +#endif + if (pair_req->oob_data_flag == BLE_SM_PAIR_OOB_YES || pair_rsp->oob_data_flag == BLE_SM_PAIR_OOB_YES) { *action = BLE_SM_IOACT_OOB_SC; @@ -137,6 +148,13 @@ ble_sm_sc_io_action(struct ble_sm_proc *proc, uint8_t *action) proc->flags |= BLE_SM_PROC_F_AUTHENTICATED; break; +#if MYNEWT_VAL(STATIC_PASSKEY) + case BLE_SM_IOACT_STATIC: + proc->pair_alg = BLE_SM_PAIR_ALG_PASSKEY; + proc->flags |= BLE_SM_PROC_F_AUTHENTICATED; + break; +#endif + case BLE_SM_IOACT_NUMCMP: proc->pair_alg = BLE_SM_PAIR_ALG_NUMCMP; proc->flags |= BLE_SM_PROC_F_AUTHENTICATED;