From e4f27cbee767d24f8e05678a484a584ec6fbe974 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Thu, 26 Nov 2020 23:49:45 +1100 Subject: [PATCH] extmod/modbluetooth: Add support for passkey authentication. Signed-off-by: Jim Mussared --- extmod/modbluetooth.c | 14 +++++++++++ extmod/modbluetooth.h | 20 ++++++++++++++++ extmod/nimble/modbluetooth_nimble.c | 37 +++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index ba5333e70e..caaf872e7d 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -689,6 +689,14 @@ STATIC mp_obj_t bluetooth_ble_gap_pair(mp_obj_t self_in, mp_obj_t conn_handle_in return bluetooth_handle_errno(mp_bluetooth_gap_pair(conn_handle)); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_gap_pair_obj, bluetooth_ble_gap_pair); + +STATIC mp_obj_t bluetooth_ble_gap_passkey(size_t n_args, const mp_obj_t *args) { + uint16_t conn_handle = mp_obj_get_int(args[1]); + uint8_t action = mp_obj_get_int(args[2]); + mp_int_t passkey = mp_obj_get_int(args[3]); + return bluetooth_handle_errno(mp_bluetooth_gap_passkey(conn_handle, action, passkey)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gap_passkey_obj, 4, 4, bluetooth_ble_gap_passkey); #endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING // ---------------------------------------------------------------------------- @@ -894,6 +902,7 @@ STATIC const mp_rom_map_elem_t bluetooth_ble_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_gap_disconnect), MP_ROM_PTR(&bluetooth_ble_gap_disconnect_obj) }, #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING { MP_ROM_QSTR(MP_QSTR_gap_pair), MP_ROM_PTR(&bluetooth_ble_gap_pair_obj) }, + { MP_ROM_QSTR(MP_QSTR_gap_passkey), MP_ROM_PTR(&bluetooth_ble_gap_passkey_obj) }, #endif // GATT Server (i.e. peripheral/advertiser role) { MP_ROM_QSTR(MP_QSTR_gatts_register_services), MP_ROM_PTR(&bluetooth_ble_gatts_register_services_obj) }, @@ -1167,6 +1176,11 @@ bool mp_bluetooth_gap_on_set_secret(uint8_t type, const uint8_t *key, size_t key mp_obj_t result = invoke_irq_handler(MP_BLUETOOTH_IRQ_SET_SECRET, args, 1, 0, NULL_ADDR, NULL_UUID, data, data_len, 2); return mp_obj_is_true(result); } + +void mp_bluetooth_gap_on_passkey_action(uint16_t conn_handle, uint8_t action, mp_int_t passkey) { + mp_int_t args[] = { conn_handle, action, passkey }; + invoke_irq_handler(MP_BLUETOOTH_IRQ_PASSKEY_ACTION, args, 2, 1, NULL_ADDR, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0); +} #endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING void mp_bluetooth_gatts_on_write(uint16_t conn_handle, uint16_t value_handle) { diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h index d79b7f56b9..f14033de30 100644 --- a/extmod/modbluetooth.h +++ b/extmod/modbluetooth.h @@ -148,6 +148,7 @@ #define MP_BLUETOOTH_IRQ_ENCRYPTION_UPDATE (28) #define MP_BLUETOOTH_IRQ_GET_SECRET (29) #define MP_BLUETOOTH_IRQ_SET_SECRET (30) +#define MP_BLUETOOTH_IRQ_PASSKEY_ACTION (31) #define MP_BLUETOOTH_ADDRESS_MODE_PUBLIC (0) #define MP_BLUETOOTH_ADDRESS_MODE_RANDOM (1) @@ -167,6 +168,12 @@ #define MP_BLUETOOTH_PASSKEY_ACTION_DISPLAY (3) #define MP_BLUETOOTH_PASSKEY_ACTION_NUMERIC_COMPARISON (4) +// These match NimBLE BLE_SM_IOACT_. +#define MP_BLUETOOTH_PASSKEY_ACTION_NONE (0) +#define MP_BLUETOOTH_PASSKEY_ACTION_INPUT (2) +#define MP_BLUETOOTH_PASSKEY_ACTION_DISPLAY (3) +#define MP_BLUETOOTH_PASSKEY_ACTION_NUMERIC_COMPARISON (4) + /* These aren't included in the module for space reasons, but can be used in your Python code if necessary. @@ -202,6 +209,7 @@ _IRQ_CONNECTION_UPDATE = const(27) _IRQ_ENCRYPTION_UPDATE = const(28) _IRQ_GET_SECRET = const(29) _IRQ_SET_SECRET = const(30) +_IRQ_PASSKEY_ACTION = const(31) _FLAG_BROADCAST = const(0x0001) _FLAG_READ = const(0x0002) @@ -231,6 +239,11 @@ _IO_CAPABILITY_DISPLAY_YESNO = const(1) _IO_CAPABILITY_KEYBOARD_ONLY = const(2) _IO_CAPABILITY_NO_INPUT_OUTPUT = const(3) _IO_CAPABILITY_KEYBOARD_DISPLAY = const(4) + +_PASSKEY_ACTION_NONE = const(0) +_PASSKEY_ACTION_INPUT = const(2) +_PASSKEY_ACTION_DISPLAY = const(3) +_PASSKEY_ACTION_NUMERIC_COMPARISON = const(4) */ // bluetooth.UUID type. @@ -332,6 +345,9 @@ int mp_bluetooth_set_preferred_mtu(uint16_t mtu); #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING // Initiate pairing on the specified connection. int mp_bluetooth_gap_pair(uint16_t conn_handle); + +// Respond to a pairing request. +int mp_bluetooth_gap_passkey(uint16_t conn_handle, uint8_t action, mp_int_t passkey); #endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE @@ -387,8 +403,12 @@ void mp_bluetooth_gatts_on_encryption_update(uint16_t conn_handle, bool encrypte // Call this when you need the application to manage persistent key data. // For get, if key is NULL, then the implementation must return the index'th matching key. Otherwise it should return a specific key. // For set, if value is NULL, then delete. +// The "type" is stack-specific, but could also be used to implement versioning. bool mp_bluetooth_gap_on_get_secret(uint8_t type, uint8_t index, const uint8_t *key, size_t key_len, const uint8_t **value, size_t *value_len); bool mp_bluetooth_gap_on_set_secret(uint8_t type, const uint8_t *key, size_t key_len, const uint8_t *value, size_t value_len); + +// Call this when a passkey verification needs to be processed. +void mp_bluetooth_gap_on_passkey_action(uint16_t conn_handle, uint8_t action, mp_int_t passkey); #endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING // Call this when a characteristic is written to. diff --git a/extmod/nimble/modbluetooth_nimble.c b/extmod/nimble/modbluetooth_nimble.c index 2b273c6bc7..ae727086ea 100644 --- a/extmod/nimble/modbluetooth_nimble.c +++ b/extmod/nimble/modbluetooth_nimble.c @@ -347,6 +347,16 @@ STATIC int gap_event_cb(struct ble_gap_event *event, void *arg) { return BLE_GAP_REPEAT_PAIRING_RETRY; } + case BLE_GAP_EVENT_PASSKEY_ACTION: { + DEBUG_printf("gap_event_cb: passkey action: conn_handle=%d action=%d num=" UINT_FMT "\n", event->passkey.conn_handle, event->passkey.params.action, (mp_uint_t)event->passkey.params.numcmp); + + #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING + mp_bluetooth_gap_on_passkey_action(event->passkey.conn_handle, event->passkey.params.action, event->passkey.params.numcmp); + #endif + + return 0; + } + default: DEBUG_printf("gap_event_cb: unknown type %d\n", event->type); break; @@ -886,6 +896,33 @@ int mp_bluetooth_gap_pair(uint16_t conn_handle) { DEBUG_printf("mp_bluetooth_gap_pair: conn_handle=%d\n", conn_handle); return ble_hs_err_to_errno(ble_gap_security_initiate(conn_handle)); } + +int mp_bluetooth_gap_passkey(uint16_t conn_handle, uint8_t action, mp_int_t passkey) { + struct ble_sm_io io = {0}; + + switch (action) { + case MP_BLUETOOTH_PASSKEY_ACTION_INPUT: { + io.passkey = passkey; + break; + } + case MP_BLUETOOTH_PASSKEY_ACTION_DISPLAY: { + io.passkey = passkey; + break; + } + case MP_BLUETOOTH_PASSKEY_ACTION_NUMERIC_COMPARISON: { + io.numcmp_accept = passkey != 0; + break; + } + default: { + return MP_EINVAL; + } + } + + io.action = action; + + DEBUG_printf("mp_bluetooth_gap_passkey: injecting IO: conn_handle=%d, action=%d, passkey=" UINT_FMT ", numcmp_accept=%d\n", conn_handle, io.action, (mp_uint_t)io.passkey, io.numcmp_accept); + return ble_hs_err_to_errno(ble_sm_inject_io(conn_handle, &io)); +} #endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE