From e38559f0a2c09303b2bf78bc3eec16e75d5299b6 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 4 Feb 2020 21:01:14 +0700 Subject: [PATCH 01/74] clean up example --- .../hid_camerashutter/hid_camerashutter.ino | 17 +++++++++++------ .../Peripheral/nrf_blinky/nrf_blinky.ino | 4 ++-- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/hid_camerashutter/hid_camerashutter.ino b/libraries/Bluefruit52Lib/examples/Peripheral/hid_camerashutter/hid_camerashutter.ino index 39aff0ac9..d44b267a2 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/hid_camerashutter/hid_camerashutter.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/hid_camerashutter/hid_camerashutter.ino @@ -14,21 +14,26 @@ /* * This sketch uses the HID Consumer Key API to send the Volume Down - * key when PIN_SHUTTER is grounded. This will cause your mobile device + * key when pinShutter is grounded. This will cause your mobile device * to capture a photo when you are in the camera app. * - * For Feather nRF52840 PIN_SHUTTER is conveniently user switch. + * For Feather nRF52840 pinShutter is conveniently user switch. */ #include BLEDis bledis; BLEHidAdafruit blehid; -#define PIN_SHUTTER 7 +// Use on-board button if available, else use A0 pin +#ifdef PIN_BUTTON1 + uint8_t pinShutter = PIN_BUTTON1; +#else + uint8_t pinShutter = A0; +#endif void setup() { - pinMode(PIN_SHUTTER, INPUT_PULLUP); + pinMode(pinShutter, INPUT_PULLUP); Serial.begin(115200); while ( !Serial ) delay(10); // for nrf52840 with native usb @@ -41,7 +46,7 @@ void setup() Serial.println("then open the camera application"); Serial.println(); - Serial.printf("Set pin %d to GND to capture a photo\n", PIN_SHUTTER); + Serial.printf("Set pin %d to GND to capture a photo\n", pinShutter); Serial.println(); Bluefruit.begin(); @@ -104,7 +109,7 @@ void startAdv(void) void loop() { // Skip if shutter pin is not Ground - if ( digitalRead(PIN_SHUTTER) == 1 ) return; + if ( digitalRead(pinShutter) == 1 ) return; // Make sure we are connected and bonded/paired for (uint16_t conn_hdl=0; conn_hdl < BLE_MAX_CONNECTION; conn_hdl++) diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/nrf_blinky/nrf_blinky.ino b/libraries/Bluefruit52Lib/examples/Peripheral/nrf_blinky/nrf_blinky.ino index 70886e52d..00c1805a5 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/nrf_blinky/nrf_blinky.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/nrf_blinky/nrf_blinky.ino @@ -62,9 +62,9 @@ BLECharacteristic lsbLED(LBS_UUID_CHR_LED); // Use on-board button if available, else use A0 pin #ifdef PIN_BUTTON1 -uint8_t button = PIN_BUTTON1; + uint8_t button = PIN_BUTTON1; #else -uint8_t button = A0; + uint8_t button = A0; #endif uint8_t buttonState; From fc922e661decacf1d63065c80d9eed35b013e25b Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 4 Feb 2020 21:06:06 +0700 Subject: [PATCH 02/74] add Bluefruit.setPIN() for static passkey pairing --- .../Bluefruit52Lib/src/BLECharacteristic.cpp | 31 ++++++++++++++++--- .../Bluefruit52Lib/src/BLECharacteristic.h | 17 ---------- libraries/Bluefruit52Lib/src/BLEService.cpp | 11 +++++++ libraries/Bluefruit52Lib/src/BLEService.h | 4 +++ libraries/Bluefruit52Lib/src/bluefruit.cpp | 26 +++++++--------- libraries/Bluefruit52Lib/src/bluefruit.h | 18 ++++------- .../Bluefruit52Lib/src/bluefruit_common.h | 19 ++++++++++++ .../Bluefruit52Lib/src/services/BLEDfu.cpp | 3 +- 8 files changed, 80 insertions(+), 49 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/BLECharacteristic.cpp b/libraries/Bluefruit52Lib/src/BLECharacteristic.cpp index 5ab0084aa..a95f5e70d 100644 --- a/libraries/Bluefruit52Lib/src/BLECharacteristic.cpp +++ b/libraries/Bluefruit52Lib/src/BLECharacteristic.cpp @@ -50,7 +50,8 @@ void BLECharacteristic::_init(void) varclr(&_properties); varclr(&_attr_meta); - _attr_meta.read_perm = _attr_meta.write_perm = BLE_SECMODE_OPEN; + _attr_meta.read_perm = BLE_SECMODE_OPEN; + _attr_meta.write_perm = BLE_SECMODE_OPEN; _attr_meta.vlen = 1; _attr_meta.vloc = BLE_GATTS_VLOC_STACK; _userbuf = NULL; @@ -212,15 +213,19 @@ ble_gatts_char_handles_t BLECharacteristic::handles(void) return _handles; } +// return the higher security mode +static inline ble_gap_conn_sec_mode_t max_secmode(ble_gap_conn_sec_mode_t sm1, ble_gap_conn_sec_mode_t sm2) +{ + if ( (sm1.sm > sm2.sm) || (sm1.sm == sm2.sm && sm1.lv > sm2.lv) ) return sm1; + return sm2; +} + err_t BLECharacteristic::begin(void) { _service = BLEService::lastService; // Add UUID128 if needed - (void) uuid.begin(); - - // Permission is OPEN if passkey is disabled. -// if (!nvm_data.core.passkey_enable) BLE_GAP_CONN_SEC_MODE_SET_OPEN(&p_char_def->permission); + uuid.begin(); // Correct Read/Write permission according to properties if ( !(_properties.read || _properties.notify || _properties.indicate ) ) @@ -233,6 +238,22 @@ err_t BLECharacteristic::begin(void) _attr_meta.write_perm = BLE_SECMODE_NO_ACCESS; } + // Correct Read/Write permission according to parent service + // Use service permission if it has higher secure mode + BleSecurityMode svc_secmode = _service->getPermission(); + ble_gap_conn_sec_mode_t svc_perm; + memcpy(&svc_perm, &svc_secmode, 1); + + if ( _attr_meta.read_perm.sm != 0 ) // skip no access + { + _attr_meta.read_perm = max_secmode(_attr_meta.read_perm, svc_perm); + } + + if ( _attr_meta.write_perm.sm != 0 ) // skip no access + { + _attr_meta.write_perm = max_secmode(_attr_meta.write_perm, svc_perm); + } + /* CCCD attribute metadata */ ble_gatts_attr_md_t cccd_md; diff --git a/libraries/Bluefruit52Lib/src/BLECharacteristic.h b/libraries/Bluefruit52Lib/src/BLECharacteristic.h index b1ac6d986..a7c92088f 100644 --- a/libraries/Bluefruit52Lib/src/BLECharacteristic.h +++ b/libraries/Bluefruit52Lib/src/BLECharacteristic.h @@ -43,23 +43,6 @@ class AdafruitBluefruit; class BLEService; -enum BleSecurityMode -{ - SECMODE_NO_ACCESS = 0x00, - SECMODE_OPEN = 0x11, - SECMODE_ENC_NO_MITM = 0x21, - SECMODE_ENC_WITH_MITM = 0x31, - SECMODE_SIGNED_NO_MITM = 0x12, - SECMODE_SIGNED_WITH_MITM = 0x22 -}; - -#define BLE_SECMODE_NO_ACCESS ((ble_gap_conn_sec_mode_t) { .sm = 0, .lv = 0 }) -#define BLE_SECMODE_OPEN ((ble_gap_conn_sec_mode_t) { .sm = 1, .lv = 1 }) -#define BLE_SECMODE_ENC_NO_MITM ((ble_gap_conn_sec_mode_t) { .sm = 1, .lv = 2 }) -#define BLE_SECMODE_ENC_WITH_MITM ((ble_gap_conn_sec_mode_t) { .sm = 1, .lv = 3 }) -#define BLE_SECMODE_SIGNED_NO_MITM ((ble_gap_conn_sec_mode_t) { .sm = 2, .lv = 1 }) -#define BLE_SECMODE_SIGNED_WITH_MITM ((ble_gap_conn_sec_mode_t) { .sm = 2, .lv = 2 }) - enum CharsProperties { CHR_PROPS_BROADCAST = bit(0), diff --git a/libraries/Bluefruit52Lib/src/BLEService.cpp b/libraries/Bluefruit52Lib/src/BLEService.cpp index b85c54f80..e108f1e5c 100644 --- a/libraries/Bluefruit52Lib/src/BLEService.cpp +++ b/libraries/Bluefruit52Lib/src/BLEService.cpp @@ -41,6 +41,7 @@ BLEService* BLEService::lastService = NULL; void BLEService::_init(void) { _handle = BLE_GATT_HANDLE_INVALID; + _permission = SECMODE_OPEN; } BLEService::BLEService(void) @@ -60,6 +61,16 @@ void BLEService::setUuid(BLEUuid bleuuid) uuid = bleuuid; } +void BLEService::setPermission(BleSecurityMode permission) +{ + _permission = permission; +} + +BleSecurityMode BLEService::getPermission(void) +{ + return _permission; +} + err_t BLEService::begin(void) { // Add UUID128 if needed diff --git a/libraries/Bluefruit52Lib/src/BLEService.h b/libraries/Bluefruit52Lib/src/BLEService.h index 8bb251d0e..d25262edd 100644 --- a/libraries/Bluefruit52Lib/src/BLEService.h +++ b/libraries/Bluefruit52Lib/src/BLEService.h @@ -43,6 +43,7 @@ class BLEService { protected: uint16_t _handle; // service gatt handle + BleSecurityMode _permission; void _init(void); @@ -59,6 +60,9 @@ class BLEService void setUuid(BLEUuid bleuuid); + void setPermission(BleSecurityMode permission); + BleSecurityMode getPermission(void); + virtual err_t begin(void); friend class BLEGatt; diff --git a/libraries/Bluefruit52Lib/src/bluefruit.cpp b/libraries/Bluefruit52Lib/src/bluefruit.cpp index d17f66e47..8ea822dc5 100644 --- a/libraries/Bluefruit52Lib/src/bluefruit.cpp +++ b/libraries/Bluefruit52Lib/src/bluefruit.cpp @@ -189,11 +189,6 @@ AdafruitBluefruit::AdafruitBluefruit(void) .kdist_own = { .enc = 1, .id = 1}, .kdist_peer = { .enc = 1, .id = 1}, }); - -COMMENT_OUT( - _auth_type = BLE_GAP_AUTH_KEY_TYPE_NONE; - varclr(_pin); -) } void AdafruitBluefruit::configServiceChanged(bool changed) @@ -658,23 +653,26 @@ void AdafruitBluefruit::setRssiCallback(rssi_callback_t fp) } -COMMENT_OUT ( +// Use Legacy SC static Passkey bool AdafruitBluefruit::setPIN(const char* pin) { VERIFY ( strlen(pin) == BLE_GAP_PASSKEY_LEN ); - _auth_type = BLE_GAP_AUTH_KEY_TYPE_PASSKEY; - memcpy(_pin, pin, BLE_GAP_PASSKEY_LEN); + // Static Passkey requires using + // - Legacy SC + // - IO cap: Display + // - MITM is on + _sec_param.lesc = 0; + _sec_param.mitm = 1; + _sec_param.bond = 1; + _sec_param.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY; -// Config Static Passkey -// ble_opt_t opt -// uint8_t passkey[] = STATIC_PASSKEY; -// m_static_pin_option.gap.passkey.p_passkey = passkey; -//err_code = sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &m_static_pin_option); + ble_opt_t opt; + opt.gap_opt.passkey.p_passkey = (const uint8_t*) pin; + VERIFY_STATUS( sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &opt), false); return true; } -) /*------------------------------------------------------------------*/ /* Thread & SoftDevice Event handler diff --git a/libraries/Bluefruit52Lib/src/bluefruit.h b/libraries/Bluefruit52Lib/src/bluefruit.h index 94d18dcc9..a2d4c8b1b 100644 --- a/libraries/Bluefruit52Lib/src/bluefruit.h +++ b/libraries/Bluefruit52Lib/src/bluefruit.h @@ -146,11 +146,6 @@ class AdafruitBluefruit bool setAppearance (uint16_t appear); uint16_t getAppearance (void); - ble_gap_sec_params_t getSecureParam(void) - { - return _sec_param; - } - void autoConnLed (bool enabled); void setConnLedInterval (uint32_t ms); @@ -173,14 +168,18 @@ class AdafruitBluefruit BLEConnection* Connection(uint16_t conn_hdl); + //--------------------------------------------------------------------+ + // Security + //--------------------------------------------------------------------+ + ble_gap_sec_params_t getSecureParam(void) { return _sec_param; } + bool setPIN(const char* pin); // Static Passkey + /*------------------------------------------------------------------*/ /* Callbacks *------------------------------------------------------------------*/ void setRssiCallback(rssi_callback_t fp); void setEventCallback( void (*fp) (ble_evt_t*) ); - COMMENT_OUT ( bool setPIN(const char* pin); ) - /*------------------------------------------------------------------*/ /* INTERNAL USAGE ONLY * Although declare as public, it is meant to be invoked by internal @@ -228,11 +227,6 @@ class AdafruitBluefruit rssi_callback_t _rssi_cb; void (*_event_cb) (ble_evt_t*); -COMMENT_OUT( - uint8_t _auth_type; - char _pin[BLE_GAP_PASSKEY_LEN]; -) - /*------------------------------------------------------------------*/ /* INTERNAL USAGE ONLY *------------------------------------------------------------------*/ diff --git a/libraries/Bluefruit52Lib/src/bluefruit_common.h b/libraries/Bluefruit52Lib/src/bluefruit_common.h index 89fde753a..2dc4da7e0 100644 --- a/libraries/Bluefruit52Lib/src/bluefruit_common.h +++ b/libraries/Bluefruit52Lib/src/bluefruit_common.h @@ -68,4 +68,23 @@ typedef void (*ble_connect_callback_t ) (uint16_t conn_hdl); typedef void (*ble_disconnect_callback_t ) (uint16_t conn_hdl, uint8_t reason); +enum BleSecurityMode +{ + SECMODE_NO_ACCESS = 0x00, + SECMODE_OPEN = 0x11, + SECMODE_ENC_NO_MITM = 0x21, + SECMODE_ENC_WITH_MITM = 0x31, + SECMODE_ENC_WITH_LESC_MITM = 0x41, // LESC MITM with 128-bit key + SECMODE_SIGNED_NO_MITM = 0x12, + SECMODE_SIGNED_WITH_MITM = 0x22 +}; + +#define BLE_SECMODE_NO_ACCESS ((ble_gap_conn_sec_mode_t) { .sm = 0, .lv = 0 }) +#define BLE_SECMODE_OPEN ((ble_gap_conn_sec_mode_t) { .sm = 1, .lv = 1 }) +#define BLE_SECMODE_ENC_NO_MITM ((ble_gap_conn_sec_mode_t) { .sm = 1, .lv = 2 }) +#define BLE_SECMODE_ENC_WITH_MITM ((ble_gap_conn_sec_mode_t) { .sm = 1, .lv = 3 }) +#define BLE_SECMODE_SIGNED_NO_MITM ((ble_gap_conn_sec_mode_t) { .sm = 2, .lv = 1 }) +#define BLE_SECMODE_SIGNED_WITH_MITM ((ble_gap_conn_sec_mode_t) { .sm = 2, .lv = 2 }) + + #endif /* BLUEFRUIT_COMMON_H_ */ diff --git a/libraries/Bluefruit52Lib/src/services/BLEDfu.cpp b/libraries/Bluefruit52Lib/src/services/BLEDfu.cpp index 94d890a5f..400e92fef 100644 --- a/libraries/Bluefruit52Lib/src/services/BLEDfu.cpp +++ b/libraries/Bluefruit52Lib/src/services/BLEDfu.cpp @@ -190,7 +190,8 @@ static void bledfu_control_wr_authorize_cb(uint16_t conn_hdl, BLECharacteristic* } } -BLEDfu::BLEDfu(void) : BLEService(UUID128_SVC_DFU_OTA), _chr_control(UUID128_CHR_DFU_CONTROL) +BLEDfu::BLEDfu(void) + : BLEService(UUID128_SVC_DFU_OTA), _chr_control(UUID128_CHR_DFU_CONTROL) { } From 8b04c264639280a3cc3feb592bfd8113f9254011 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 4 Feb 2020 21:13:11 +0700 Subject: [PATCH 03/74] rename BleSecurityMode to SecureMode_t --- libraries/Bluefruit52Lib/src/BLECharacteristic.cpp | 6 +++--- libraries/Bluefruit52Lib/src/BLECharacteristic.h | 4 ++-- libraries/Bluefruit52Lib/src/BLEService.cpp | 4 ++-- libraries/Bluefruit52Lib/src/BLEService.h | 6 +++--- libraries/Bluefruit52Lib/src/bluefruit_common.h | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/BLECharacteristic.cpp b/libraries/Bluefruit52Lib/src/BLECharacteristic.cpp index a95f5e70d..3f20243a2 100644 --- a/libraries/Bluefruit52Lib/src/BLECharacteristic.cpp +++ b/libraries/Bluefruit52Lib/src/BLECharacteristic.cpp @@ -148,7 +148,7 @@ void BLECharacteristic::setBuffer(void* buf, uint16_t bufsize) _attr_meta.vloc = buf ? BLE_GATTS_VLOC_USER : BLE_GATTS_VLOC_STACK; } -void BLECharacteristic::setPermission(BleSecurityMode read_perm, BleSecurityMode write_perm) +void BLECharacteristic::setPermission(SecureMode_t read_perm, SecureMode_t write_perm) { memcpy(&_attr_meta.read_perm , &read_perm, 1); memcpy(&_attr_meta.write_perm, &write_perm, 1); @@ -240,7 +240,7 @@ err_t BLECharacteristic::begin(void) // Correct Read/Write permission according to parent service // Use service permission if it has higher secure mode - BleSecurityMode svc_secmode = _service->getPermission(); + SecureMode_t svc_secmode = _service->getPermission(); ble_gap_conn_sec_mode_t svc_perm; memcpy(&svc_perm, &svc_secmode, 1); @@ -348,7 +348,7 @@ err_t BLECharacteristic::begin(void) return ERROR_NONE; } -err_t BLECharacteristic::addDescriptor(BLEUuid bleuuid, void const * content, uint16_t len, BleSecurityMode read_perm, BleSecurityMode write_perm) +err_t BLECharacteristic::addDescriptor(BLEUuid bleuuid, void const * content, uint16_t len, SecureMode_t read_perm, SecureMode_t write_perm) { // Meta Data ble_gatts_attr_md_t meta; diff --git a/libraries/Bluefruit52Lib/src/BLECharacteristic.h b/libraries/Bluefruit52Lib/src/BLECharacteristic.h index a7c92088f..343b0ae17 100644 --- a/libraries/Bluefruit52Lib/src/BLECharacteristic.h +++ b/libraries/Bluefruit52Lib/src/BLECharacteristic.h @@ -78,7 +78,7 @@ class BLECharacteristic /*------------- Configure -------------*/ void setUuid(BLEUuid bleuuid); void setProperties(uint8_t prop); - void setPermission(BleSecurityMode read_perm, BleSecurityMode write_perm); + void setPermission(SecureMode_t read_perm, SecureMode_t write_perm); void setMaxLen(uint16_t max_len); void setFixedLen(uint16_t fixed_len); void setBuffer(void* buf, uint16_t bufsize); @@ -99,7 +99,7 @@ class BLECharacteristic virtual err_t begin(void); // Add Descriptor function must be called right after begin() - err_t addDescriptor(BLEUuid bleuuid, void const * content, uint16_t len, BleSecurityMode read_perm = SECMODE_OPEN, BleSecurityMode write_perm = SECMODE_NO_ACCESS); + err_t addDescriptor(BLEUuid bleuuid, void const * content, uint16_t len, SecureMode_t read_perm = SECMODE_OPEN, SecureMode_t write_perm = SECMODE_NO_ACCESS); ble_gatts_char_handles_t handles(void); diff --git a/libraries/Bluefruit52Lib/src/BLEService.cpp b/libraries/Bluefruit52Lib/src/BLEService.cpp index e108f1e5c..05bdd99cd 100644 --- a/libraries/Bluefruit52Lib/src/BLEService.cpp +++ b/libraries/Bluefruit52Lib/src/BLEService.cpp @@ -61,12 +61,12 @@ void BLEService::setUuid(BLEUuid bleuuid) uuid = bleuuid; } -void BLEService::setPermission(BleSecurityMode permission) +void BLEService::setPermission(SecureMode_t permission) { _permission = permission; } -BleSecurityMode BLEService::getPermission(void) +SecureMode_t BLEService::getPermission(void) { return _permission; } diff --git a/libraries/Bluefruit52Lib/src/BLEService.h b/libraries/Bluefruit52Lib/src/BLEService.h index d25262edd..d7e02c1e7 100644 --- a/libraries/Bluefruit52Lib/src/BLEService.h +++ b/libraries/Bluefruit52Lib/src/BLEService.h @@ -43,7 +43,7 @@ class BLEService { protected: uint16_t _handle; // service gatt handle - BleSecurityMode _permission; + SecureMode_t _permission; void _init(void); @@ -60,8 +60,8 @@ class BLEService void setUuid(BLEUuid bleuuid); - void setPermission(BleSecurityMode permission); - BleSecurityMode getPermission(void); + void setPermission(SecureMode_t permission); + SecureMode_t getPermission(void); virtual err_t begin(void); diff --git a/libraries/Bluefruit52Lib/src/bluefruit_common.h b/libraries/Bluefruit52Lib/src/bluefruit_common.h index 2dc4da7e0..b8004c39b 100644 --- a/libraries/Bluefruit52Lib/src/bluefruit_common.h +++ b/libraries/Bluefruit52Lib/src/bluefruit_common.h @@ -68,7 +68,7 @@ typedef void (*ble_connect_callback_t ) (uint16_t conn_hdl); typedef void (*ble_disconnect_callback_t ) (uint16_t conn_hdl, uint8_t reason); -enum BleSecurityMode +enum SecureMode_t { SECMODE_NO_ACCESS = 0x00, SECMODE_OPEN = 0x11, From 2c02b37d91a983b54fc29cc93893e65a3100a7ca Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 4 Feb 2020 22:13:15 +0700 Subject: [PATCH 04/74] add PIN Pairing example --- .../examples/Peripheral/bleuart/bleuart.ino | 2 +- .../hid_camerashutter/hid_camerashutter.ino | 2 - .../Peripheral/pairing_pin/pairing_pin.ino | 149 ++++++++++++++++++ libraries/Bluefruit52Lib/src/bluefruit.cpp | 38 +++-- 4 files changed, 174 insertions(+), 17 deletions(-) create mode 100644 libraries/Bluefruit52Lib/examples/Peripheral/pairing_pin/pairing_pin.ino diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/bleuart/bleuart.ino b/libraries/Bluefruit52Lib/examples/Peripheral/bleuart/bleuart.ino index b1624fa40..73acefca6 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/bleuart/bleuart.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/bleuart/bleuart.ino @@ -30,7 +30,7 @@ void setup() Serial.println("---------------------------\n"); // Setup the BLE LED to be enabled on CONNECT - // Note: This is actually the default behaviour, but provided + // Note: This is actually the default behavior, but provided // here in case you want to control this LED manually via PIN 19 Bluefruit.autoConnLed(true); diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/hid_camerashutter/hid_camerashutter.ino b/libraries/Bluefruit52Lib/examples/Peripheral/hid_camerashutter/hid_camerashutter.ino index d44b267a2..3bcabdb8e 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/hid_camerashutter/hid_camerashutter.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/hid_camerashutter/hid_camerashutter.ino @@ -16,8 +16,6 @@ * This sketch uses the HID Consumer Key API to send the Volume Down * key when pinShutter is grounded. This will cause your mobile device * to capture a photo when you are in the camera app. - * - * For Feather nRF52840 pinShutter is conveniently user switch. */ #include diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_pin/pairing_pin.ino b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_pin/pairing_pin.ino new file mode 100644 index 000000000..b6c6640e7 --- /dev/null +++ b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_pin/pairing_pin.ino @@ -0,0 +1,149 @@ +/********************************************************************* + This is an example for our nRF52 based Bluefruit LE modules + + Pick one up today in the adafruit shop! + + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +/* This sketch demonstrates Pairing process using static Passkey aka PIN. + * This sketch is essentially the same as bleuart.ino except the BLE Uart + * service requires Security Mode with Man-In-The-Middle protection i.e + * using 6 digits PIN for pairing. + */ + +#include +#include +#include + +// Static PIN is 6 digits from 000000-999999 +#define PAIRING_PIN "123456" + +// BLE Service +BLEUart bleuart; // uart over ble + +void setup() +{ + Serial.begin(115200); + while ( !Serial ) delay(10); // for nrf52840 with native usb + + Serial.println("Bluefruit52 BLEUART Example"); + Serial.println("---------------------------\n"); + + // Setup the BLE LED to be enabled on CONNECT + // Note: This is actually the default behaviour, but provided + // here in case you want to control this LED manually via PIN 19 + Bluefruit.autoConnLed(true); + + // Config the peripheral connection with maximum bandwidth + // more SRAM required by SoftDevice + // Note: All config***() function must be called before begin() + Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); + + Bluefruit.begin(); + Bluefruit.setTxPower(4); // Check bluefruit.h for supported values + Bluefruit.setName("Bluefruit52"); + + Serial.println("Setting pairing PIN to: " PAIRING_PIN); + Bluefruit.setPIN(PAIRING_PIN); + + Bluefruit.Periph.setConnectCallback(connect_callback); + Bluefruit.Periph.setDisconnectCallback(disconnect_callback); + + // Configure and Start BLE Uart Service + // Set Permission to access BLE Uart is to require man-in-the-middle protection + // This will cause central to perform pairing with static PIN we set above + Serial.println("Configure BLE Uart to require man-in-the-middle protection for PIN pairing"); + bleuart.setPermission(SECMODE_ENC_WITH_MITM); + bleuart.begin(); + + // Set up and start advertising + startAdv(); + + Serial.println("Please use Adafruit's Bluefruit LE app to connect in UART mode"); + Serial.println("Your phone should pop-up PIN input"); + Serial.println("Once connected, enter character(s) that you wish to send"); +} + +void startAdv(void) +{ + // Advertising packet + Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); + Bluefruit.Advertising.addTxPower(); + + // Include bleuart 128-bit uuid + Bluefruit.Advertising.addService(bleuart); + + // Secondary Scan Response packet (optional) + // Since there is no room for 'Name' in Advertising packet + Bluefruit.ScanResponse.addName(); + + /* Start Advertising + * - Enable auto advertising if disconnected + * - Interval: fast mode = 20 ms, slow mode = 152.5 ms + * - Timeout for fast mode is 30 seconds + * - Start(timeout) with timeout = 0 will advertise forever (until connected) + * + * For recommended advertising interval + * https://developer.apple.com/library/content/qa/qa1931/_index.html + */ + Bluefruit.Advertising.restartOnDisconnect(true); + Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms + Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode + Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds +} + +void loop() +{ + // Forward data from HW Serial to BLEUART + while (Serial.available()) + { + // Delay to wait for enough input, since we have a limited transmission buffer + delay(2); + + uint8_t buf[64]; + int count = Serial.readBytes(buf, sizeof(buf)); + bleuart.write( buf, count ); + } + + // Forward from BLEUART to HW Serial + while ( bleuart.available() ) + { + uint8_t ch; + ch = (uint8_t) bleuart.read(); + Serial.write(ch); + } +} + +// callback invoked when central connects +void connect_callback(uint16_t conn_handle) +{ + // Get the reference to current connection + BLEConnection* connection = Bluefruit.Connection(conn_handle); + + char central_name[32] = { 0 }; + connection->getPeerName(central_name, sizeof(central_name)); + + Serial.print("Connected to "); + Serial.println(central_name); +} + +/** + * Callback invoked when a connection is dropped + * @param conn_handle connection where this event happens + * @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h + */ +void disconnect_callback(uint16_t conn_handle, uint8_t reason) +{ + (void) conn_handle; + (void) reason; + + Serial.println(); + Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX); +} diff --git a/libraries/Bluefruit52Lib/src/bluefruit.cpp b/libraries/Bluefruit52Lib/src/bluefruit.cpp index 8ea822dc5..3b091ef12 100644 --- a/libraries/Bluefruit52Lib/src/bluefruit.cpp +++ b/libraries/Bluefruit52Lib/src/bluefruit.cpp @@ -656,20 +656,30 @@ void AdafruitBluefruit::setRssiCallback(rssi_callback_t fp) // Use Legacy SC static Passkey bool AdafruitBluefruit::setPIN(const char* pin) { - VERIFY ( strlen(pin) == BLE_GAP_PASSKEY_LEN ); - - // Static Passkey requires using - // - Legacy SC - // - IO cap: Display - // - MITM is on - _sec_param.lesc = 0; - _sec_param.mitm = 1; - _sec_param.bond = 1; - _sec_param.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY; - - ble_opt_t opt; - opt.gap_opt.passkey.p_passkey = (const uint8_t*) pin; - VERIFY_STATUS( sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &opt), false); + // back to open mode + if (pin == NULL) + { + _sec_param.lesc = 0; + _sec_param.mitm = 0; + _sec_param.bond = 1; + _sec_param.io_caps = BLE_GAP_IO_CAPS_NONE; + }else + { + VERIFY ( strlen(pin) == BLE_GAP_PASSKEY_LEN ); + + // Static Passkey requires using + // - Legacy SC + // - IO cap: Display + // - MITM is on + _sec_param.lesc = 0; + _sec_param.mitm = 1; + _sec_param.bond = 1; + _sec_param.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY; + + ble_opt_t opt; + opt.gap_opt.passkey.p_passkey = (const uint8_t*) pin; + VERIFY_STATUS( sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &opt), false); + } return true; } From ee29722b693f891ca77c0ee58f895ce692db21fd Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 5 Feb 2020 14:57:42 +0700 Subject: [PATCH 05/74] adding pairing display example --- .../pairing_display/pairing_display.ino | 273 ++++++++++++++++++ .../Peripheral/pairing_pin/pairing_pin.ino | 2 +- .../Bluefruit52Lib/src/BLEConnection.cpp | 43 ++- libraries/Bluefruit52Lib/src/bluefruit.cpp | 65 ++++- libraries/Bluefruit52Lib/src/bluefruit.h | 18 +- 5 files changed, 367 insertions(+), 34 deletions(-) create mode 100644 libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino new file mode 100644 index 000000000..fc67c640c --- /dev/null +++ b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino @@ -0,0 +1,273 @@ +/********************************************************************* + This is an example for our nRF52 based Bluefruit LE modules + + Pick one up today in the adafruit shop! + + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +#include +#include +#include +#include +#include + +/* This sketch demonstrates Pairing process using static Passkey aka PIN. + * This sketch is essentially the same as bleuart.ino except the BLE Uart + * service requires Security Mode with Man-In-The-Middle protection i.e + * using 6 digits PIN for pairing. + */ + +/* This sketch demonstrates the "Image Upload" feature of Bluefruit Mobile App. + * Following TFT Display are supported + * - https://www.adafruit.com/product/3315 + * - https://www.adafruit.com/product/3651 + * - https://www.adafruit.com/product/4367 + */ + +#define TFT_NONE 0 +#define TFT_35_FEATHERWING 1 +#define TFT_24_FEATHERWING 2 +#define TFT_GIZMO 3 + +// [Configurable] Please select one of above supported Display to match your hardware setup +#define TFT_IN_USE TFT_NONE + + +#if defined(ARDUINO_NRF52832_FEATHER) + // Feather nRF52832 + #define TFT_DC 11 + #define TFT_CS 31 + +#elif defined(ARDUINO_NRF52840_CIRCUITPLAY) + // Circuit Playground Bluefruit for use with TFT 1.5" GIZMO + #define TFT_DC 1 + #define TFT_CS 0 + #define TFT_BACKLIGHT A3 + +#else + // Default for others + #define TFT_DC 10 + #define TFT_CS 9 +#endif + + +#if TFT_IN_USE == TFT_35_FEATHERWING + #include "Adafruit_HX8357.h" + Adafruit_HX8357 tft = Adafruit_HX8357(TFT_CS, TFT_DC); + +#elif TFT_IN_USE == TFT_24_FEATHERWING + #include + Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); + +#elif TFT_IN_USE == TFT_GIZMO + #include "Adafruit_ST7789.h" + Adafruit_ST7789 tft = Adafruit_ST7789(&SPI, TFT_CS, TFT_DC, -1); + +#endif + +#define COLOR_WHITE 0xFFFF +#define COLOR_BLACK 0x0000 +#define COLOR_YELLOW 0xFFE0 +#define COLOR_GREEN 0x07E0 +#define COLOR_RED 0xF800 + +// BLE Service +BLEUart bleuart; // uart over ble + +void setup() +{ + Serial.begin(115200); + +#if TFT_IN_USE == TFT_GIZMO + tft.init(240, 240); + tft.setRotation(2); + pinMode(TFT_BACKLIGHT, OUTPUT); + digitalWrite(TFT_BACKLIGHT, HIGH); // Backlight on + +#elif TFT_IN_USE != TFT_NONE + tft.begin(); + +#endif + + Serial.println("Bluefruit52 BLEUART Example"); + Serial.println("---------------------------\n"); + + // Setup the BLE LED to be enabled on CONNECT + // Note: This is actually the default behavior, but provided + // here in case you want to control this LED manually via PIN 19 + Bluefruit.autoConnLed(true); + + // Config the peripheral connection with maximum bandwidth + // more SRAM required by SoftDevice + // Note: All config***() function must be called before begin() + Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); + + Bluefruit.begin(); + Bluefruit.setTxPower(4); // Check bluefruit.h for supported values + Bluefruit.setName("Bluefruit52"); + +// Serial.println("Setting pairing PIN to: " PAIRING_PIN); + Bluefruit.setPairingDisplayCallback(pairing_display_callback); + Bluefruit.setPairingCompleteCallback(pairing_complete_callback); + + Bluefruit.Periph.setConnectCallback(connect_callback); + Bluefruit.Periph.setDisconnectCallback(disconnect_callback); + + // Configure and Start BLE Uart Service + // Set Permission to access BLE Uart is to require man-in-the-middle protection + // This will cause central to perform pairing with static PIN we set above + Serial.println("Configure BLE Uart to require man-in-the-middle protection for PIN pairing"); + bleuart.setPermission(SECMODE_ENC_WITH_MITM); + bleuart.begin(); + + // Set up and start advertising + startAdv(); + + Serial.println("Please use Adafruit's Bluefruit LE app to connect in UART mode"); + Serial.println("Your phone should pop-up PIN input"); + Serial.println("Once connected, enter character(s) that you wish to send"); + +#if TFT_IN_USE != TFT_NONE + tft.fillScreen(COLOR_BLACK); + tft.setTextColor(COLOR_WHITE); + tft.setTextSize(2); + tft.println("Advertising ... "); +#endif +} + +void startAdv(void) +{ + // Advertising packet + Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); + Bluefruit.Advertising.addTxPower(); + + // Include bleuart 128-bit uuid + Bluefruit.Advertising.addService(bleuart); + + // Secondary Scan Response packet (optional) + // Since there is no room for 'Name' in Advertising packet + Bluefruit.ScanResponse.addName(); + + /* Start Advertising + * - Enable auto advertising if disconnected + * - Interval: fast mode = 20 ms, slow mode = 152.5 ms + * - Timeout for fast mode is 30 seconds + * - Start(timeout) with timeout = 0 will advertise forever (until connected) + * + * For recommended advertising interval + * https://developer.apple.com/library/content/qa/qa1931/_index.html + */ + Bluefruit.Advertising.restartOnDisconnect(true); + Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms + Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode + Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds +} + +void loop() +{ + // Forward data from HW Serial to BLEUART + while (Serial.available()) + { + // Delay to wait for enough input, since we have a limited transmission buffer + delay(2); + + uint8_t buf[64]; + int count = Serial.readBytes(buf, sizeof(buf)); + bleuart.write( buf, count ); + } + + // Forward from BLEUART to HW Serial + while ( bleuart.available() ) + { + uint8_t ch; + ch = (uint8_t) bleuart.read(); + Serial.write(ch); + } +} + +void pairing_display_callback(uint16_t conn_handle, uint8_t const passkey[6]) +{ + Serial.println("Enter this code on your phone to pair with Bluefruit:"); + Serial.printf(" %.6s\n", passkey); + +#if TFT_IN_USE != TFT_NONE + tft.printf("Enter this code on your phone to pair with Bluefruit:\n\n"); + tft.setTextColor(COLOR_YELLOW); + tft.setTextSize(4); + tft.printf(" %.6s\n", passkey); + + tft.setTextColor(COLOR_WHITE); + tft.setTextSize(2); +#endif +} + +void pairing_complete_callback(uint16_t conn_handle, uint8_t auth_status) +{ + if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS) + { + Serial.println("Succeeded"); + }else + { + Serial.println("Failed"); + } + +#if TFT_IN_USE != TFT_NONE + if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS) + { + tft.setTextColor(COLOR_GREEN); + tft.println("Succeeded"); + }else + { + tft.setTextColor(COLOR_RED); + tft.println("Failed"); + } + + tft.setTextColor(COLOR_WHITE); + tft.setTextSize(2); +#endif +} + +// callback invoked when central connects +void connect_callback(uint16_t conn_handle) +{ + // Get the reference to current connection + BLEConnection* connection = Bluefruit.Connection(conn_handle); + + char central_name[32] = { 0 }; + connection->getPeerName(central_name, sizeof(central_name)); + + Serial.print("Connected to "); + Serial.println(central_name); + +#if TFT_IN_USE != TFT_NONE + tft.fillScreen(COLOR_BLACK); + tft.setTextSize(2); + tft.setCursor(0, 0); + tft.println("Connected"); +#endif +} + +/** + * Callback invoked when a connection is dropped + * @param conn_handle connection where this event happens + * @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h + */ +void disconnect_callback(uint16_t conn_handle, uint8_t reason) +{ + (void) conn_handle; + (void) reason; + + Serial.println(); + Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX); + +#if TFT_IN_USE != TFT_NONE + tft.println("Advertising ..."); +#endif +} diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_pin/pairing_pin.ino b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_pin/pairing_pin.ino index b6c6640e7..8e914c054 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_pin/pairing_pin.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_pin/pairing_pin.ino @@ -37,7 +37,7 @@ void setup() Serial.println("---------------------------\n"); // Setup the BLE LED to be enabled on CONNECT - // Note: This is actually the default behaviour, but provided + // Note: This is actually the default behavior, but provided // here in case you want to control this LED manually via PIN 19 Bluefruit.autoConnLed(true); diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.cpp b/libraries/Bluefruit52Lib/src/BLEConnection.cpp index 269fb1c78..9f858aaac 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.cpp +++ b/libraries/Bluefruit52Lib/src/BLEConnection.cpp @@ -304,7 +304,7 @@ void BLEConnection::_eventHandler(ble_evt_t* evt) //--------------------------------------------------------------------+ /* First-time Pairing - * Connect -> SEC_PARAMS_REQUEST -> CONN_SEC_UPDATE -> AUTH_STATUS + * Connect -> SEC_PARAMS_REQUEST -> PASSKEY_DISPLAY -> CONN_SEC_UPDATE -> AUTH_STATUS * 1. Either we or peer initiate the process * 2. Peer ask for Secure Parameter ( I/O Caps ) BLE_GAP_EVT_SEC_PARAMS_REQUEST * 3. Pair Key exchange ( PIN code) @@ -331,15 +331,10 @@ void BLEConnection::_eventHandler(ble_evt_t* evt) * - Central supplies its parameters * - We replies with our security parameters */ - // ble_gap_sec_params_t* peer = &evt->evt.gap_evt.params.sec_params_request.peer_params; - COMMENT_OUT( - // Change security parameter according to authentication type - if ( _auth_type == BLE_GAP_AUTH_KEY_TYPE_PASSKEY) - { - sec_para.mitm = 1; - sec_para.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY; - } - ) + ble_gap_sec_params_t const* peer = &evt->evt.gap_evt.params.sec_params_request.peer_params; + (void) peer; + LOG_LV2("PAIR", "Peer Params: bond = %d, mitm = %d, lesc = %d, io_caps = %d", + peer->bond, peer->mitm, peer->lesc, peer->io_caps); ble_gap_sec_keyset_t keyset = { @@ -372,6 +367,8 @@ void BLEConnection::_eventHandler(ble_evt_t* evt) // Pairing process completed ble_gap_evt_auth_status_t* status = &evt->evt.gap_evt.params.auth_status; + LOG_LV2("PAIR", "Auth Status = 0x%02x (BLE_GAP_SEC_STATUS)", status->auth_status); + // Pairing succeeded --> save encryption keys ( Bonding ) if (BLE_GAP_SEC_STATUS_SUCCESS == status->auth_status) { @@ -379,9 +376,6 @@ void BLEConnection::_eventHandler(ble_evt_t* evt) _ediv = _bond_keys->own_enc.master_id.ediv; bond_save_keys(_role, _conn_hdl, _bond_keys); - }else - { - PRINT_HEX(status->auth_status); } rtos_free(_bond_keys); @@ -411,15 +405,20 @@ void BLEConnection::_eventHandler(ble_evt_t* evt) } break; - case BLE_GAP_EVT_PASSKEY_DISPLAY: - { - // ble_gap_evt_passkey_display_t const* passkey_display = &evt->evt.gap_evt.params.passkey_display; - // PRINT_INT(passkey_display->match_request); - // PRINT_BUFFER(passkey_display->passkey, 6); - - // sd_ble_gap_auth_key_reply - } - break; +// case BLE_GAP_EVT_PASSKEY_DISPLAY: +// { +// ble_gap_evt_passkey_display_t const* passkey_display = &evt->evt.gap_evt.params.passkey_display; +// LOG_LV2("PAIR", "Passkey = %.6s, match request = %d", passkey_display->passkey, passkey_display->match_request); +// +// if ( Bluefruit._pair_display_cb ) ada_callback(passkey_display->passkey, 6, ) +// +// if (passkey_display->match_request) +// { +// // Match request require to report the match +// // sd_ble_gap_auth_key_reply(); +// } +// } +// break; case BLE_GAP_EVT_CONN_SEC_UPDATE: { diff --git a/libraries/Bluefruit52Lib/src/bluefruit.cpp b/libraries/Bluefruit52Lib/src/bluefruit.cpp index 3b091ef12..276692ba3 100644 --- a/libraries/Bluefruit52Lib/src/bluefruit.cpp +++ b/libraries/Bluefruit52Lib/src/bluefruit.cpp @@ -175,6 +175,7 @@ AdafruitBluefruit::AdafruitBluefruit(void) _event_cb = NULL; _rssi_cb = NULL; + _pair_display_cb = NULL; _sec_param = ((ble_gap_sec_params_t) { @@ -621,7 +622,7 @@ bool AdafruitBluefruit::disconnect(uint16_t conn_hdl) return true; // not connected still return true } -void AdafruitBluefruit::setEventCallback ( void (*fp) (ble_evt_t*) ) +void AdafruitBluefruit::setEventCallback (event_cb_t fp) { _event_cb = fp; } @@ -647,7 +648,7 @@ BLEConnection* AdafruitBluefruit::Connection(uint16_t conn_hdl) return (conn_hdl < BLE_MAX_CONNECTION) ? _connection[conn_hdl] : NULL; } -void AdafruitBluefruit::setRssiCallback(rssi_callback_t fp) +void AdafruitBluefruit::setRssiCallback(rssi_cb_t fp) { _rssi_cb = fp; } @@ -659,9 +660,9 @@ bool AdafruitBluefruit::setPIN(const char* pin) // back to open mode if (pin == NULL) { - _sec_param.lesc = 0; - _sec_param.mitm = 0; _sec_param.bond = 1; + _sec_param.mitm = 0; + _sec_param.lesc = 0; _sec_param.io_caps = BLE_GAP_IO_CAPS_NONE; }else { @@ -671,9 +672,9 @@ bool AdafruitBluefruit::setPIN(const char* pin) // - Legacy SC // - IO cap: Display // - MITM is on - _sec_param.lesc = 0; - _sec_param.mitm = 1; _sec_param.bond = 1; + _sec_param.mitm = 1; + _sec_param.lesc = 0; _sec_param.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY; ble_opt_t opt; @@ -684,6 +685,34 @@ bool AdafruitBluefruit::setPIN(const char* pin) return true; } +// Pairing using LESC with peripheral display +bool AdafruitBluefruit::setPairingDisplayCallback(pair_display_cb_t fp) +{ + _pair_display_cb = fp; + + if ( fp == NULL ) + { + // TODO callback clear + }else + { + _sec_param.bond = 1; + _sec_param.mitm = 1; + _sec_param.lesc = 0; + _sec_param.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY; + + ble_opt_t opt; + opt.gap_opt.passkey.p_passkey = NULL; // generate Passkey randomly + VERIFY_STATUS( sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &opt), false); + } + + return true; +} + +void AdafruitBluefruit::setPairingCompleteCallback(pair_complete_cb_t fp) +{ + _pair_complete_cb = fp; +} + /*------------------------------------------------------------------*/ /* Thread & SoftDevice Event handler *------------------------------------------------------------------*/ @@ -868,6 +897,30 @@ void AdafruitBluefruit::_ble_handler(ble_evt_t* evt) } break; + case BLE_GAP_EVT_PASSKEY_DISPLAY: + { + ble_gap_evt_passkey_display_t const* passkey_display = &evt->evt.gap_evt.params.passkey_display; + LOG_LV2("PAIR", "Passkey = %.6s, match request = %d", passkey_display->passkey, passkey_display->match_request); + + // Invoke display callback + if ( _pair_display_cb ) ada_callback(passkey_display->passkey, 6, _pair_display_cb, conn_hdl, passkey_display->passkey); + + if (passkey_display->match_request) + { + // Match request require to report the match + // sd_ble_gap_auth_key_reply(); + } + } + break; + + case BLE_GAP_EVT_AUTH_STATUS: + { + ble_gap_evt_auth_status_t* status = &evt->evt.gap_evt.params.auth_status; + + if (_pair_complete_cb) ada_callback(NULL, 0, _pair_complete_cb, conn_hdl, status->auth_status); + } + break; + case BLE_EVT_USER_MEM_REQUEST: // We will handle Long Write sequence (RW Authorize PREP_WRITE_REQ) sd_ble_user_mem_reply(conn_hdl, NULL); diff --git a/libraries/Bluefruit52Lib/src/bluefruit.h b/libraries/Bluefruit52Lib/src/bluefruit.h index a2d4c8b1b..e3b14db6c 100644 --- a/libraries/Bluefruit52Lib/src/bluefruit.h +++ b/libraries/Bluefruit52Lib/src/bluefruit.h @@ -95,7 +95,10 @@ extern "C" class AdafruitBluefruit { public: - typedef void (*rssi_callback_t) (uint16_t conn_hdl, int8_t rssi); + typedef void (*event_cb_t) (ble_evt_t* evt); + typedef void (*rssi_cb_t) (uint16_t conn_hdl, int8_t rssi); + typedef void (*pair_display_cb_t ) (uint16_t conn_hdl, uint8_t const passkey[6]); + typedef void (*pair_complete_cb_t) (uint16_t conn_hdl, uint8_t auth_status); AdafruitBluefruit(void); // Constructor @@ -173,12 +176,14 @@ class AdafruitBluefruit //--------------------------------------------------------------------+ ble_gap_sec_params_t getSecureParam(void) { return _sec_param; } bool setPIN(const char* pin); // Static Passkey + bool setPairingDisplayCallback(pair_display_cb_t fp); + void setPairingCompleteCallback(pair_complete_cb_t fp); /*------------------------------------------------------------------*/ /* Callbacks *------------------------------------------------------------------*/ - void setRssiCallback(rssi_callback_t fp); - void setEventCallback( void (*fp) (ble_evt_t*) ); + void setRssiCallback(rssi_cb_t fp); + void setEventCallback(event_cb_t fp); /*------------------------------------------------------------------*/ /* INTERNAL USAGE ONLY @@ -224,8 +229,11 @@ class AdafruitBluefruit BLEConnection* _connection[BLE_MAX_CONNECTION]; - rssi_callback_t _rssi_cb; - void (*_event_cb) (ble_evt_t*); + //------------- Callbacks -------------// + rssi_cb_t _rssi_cb; + event_cb_t _event_cb; + pair_display_cb_t _pair_display_cb; + pair_complete_cb_t _pair_complete_cb; /*------------------------------------------------------------------*/ /* INTERNAL USAGE ONLY From e867aca49f502297ede33131366e153d13cad54e Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 11 Feb 2020 00:10:01 +0700 Subject: [PATCH 06/74] add linker {compiler.libraries.ldflags} --- platform.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform.txt b/platform.txt index efea43618..be7751bff 100644 --- a/platform.txt +++ b/platform.txt @@ -88,7 +88,7 @@ recipe.S.o.pattern="{compiler.path}{compiler.S.cmd}" {compiler.S.flags} -DF_CPU= recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{archive_file_path}" "{object_file}" ## Combine gc-sections, archives, and objects -recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" "-L{build.path}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} "-L{build.core.path}/linker" "-T{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.ldflags} -o "{build.path}/{build.project_name}.elf" {object_files} -Wl,--start-group -lm "{build.path}/{archive_file}" -Wl,--end-group +recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" "-L{build.path}" "-L{build.core.path}/linker" "-T{build.ldscript}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.ldflags} -o "{build.path}/{build.project_name}.elf" {object_files} {compiler.libraries.ldflags} -Wl,--start-group -lm "{build.path}/{archive_file}" -Wl,--end-group ## Create output (bin file) #recipe.objcopy.bin.pattern="{compiler.path}{compiler.elf2bin.cmd}" {compiler.elf2bin.flags} {compiler.elf2bin.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.bin" From 7fd7285708571048978f0069f86ebbbbcfd389ab Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 11 Feb 2020 16:49:17 +0700 Subject: [PATCH 07/74] clean up --- platform.txt | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/platform.txt b/platform.txt index be7751bff..57b3cdfbc 100644 --- a/platform.txt +++ b/platform.txt @@ -30,21 +30,27 @@ compiler.warning_flags.all=-Wall -Wextra -Wno-unused-parameter -Wno-missing-fiel compiler.path={runtime.tools.arm-none-eabi-gcc.path}/bin/ compiler.c.cmd=arm-none-eabi-gcc -compiler.c.flags=-mcpu={build.mcu} -mthumb -c -g {compiler.warning_flags} {build.float_flags} -std=gnu11 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -MMD +compiler.c.flags=-mcpu={build.mcu} -mthumb -c -g {compiler.warning_flags} {build.float_flags} -std=gnu11 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -MMD -Ofast + compiler.c.elf.cmd=arm-none-eabi-gcc compiler.c.elf.flags=-Ofast -Wl,--gc-sections -save-temps + compiler.S.cmd=arm-none-eabi-gcc -compiler.S.flags=-c -g -x assembler-with-cpp +compiler.S.flags=-c -g -x assembler-with-cpp -Ofast + compiler.cpp.cmd=arm-none-eabi-g++ -compiler.cpp.flags=-mcpu={build.mcu} -mthumb -c -g {compiler.warning_flags} {build.float_flags} -std=gnu++11 -ffunction-sections -fdata-sections -fno-threadsafe-statics -nostdlib --param max-inline-insns-single=500 -fno-rtti -fno-exceptions -MMD +compiler.cpp.flags=-mcpu={build.mcu} -mthumb -c -g {compiler.warning_flags} {build.float_flags} -std=gnu++11 -ffunction-sections -fdata-sections -fno-threadsafe-statics -nostdlib --param max-inline-insns-single=500 -fno-rtti -fno-exceptions -MMD -Ofast compiler.ar.cmd=arm-none-eabi-ar compiler.ar.flags=rcs + compiler.objcopy.cmd=arm-none-eabi-objcopy compiler.objcopy.eep.flags=-O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 + compiler.elf2bin.flags=-O binary compiler.elf2bin.cmd=arm-none-eabi-objcopy compiler.elf2hex.flags=-O ihex compiler.elf2hex.cmd=arm-none-eabi-objcopy + compiler.ldflags=-mcpu={build.mcu} -mthumb {build.float_flags} -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align --specs=nano.specs --specs=nosys.specs compiler.size.cmd=arm-none-eabi-size @@ -57,7 +63,7 @@ rtos.path={build.core.path}/freertos nordic.path={build.core.path}/nordic -build.flags.nrf= -DSOFTDEVICE_PRESENT -DARDUINO_NRF52_ADAFRUIT -DNRF52_SERIES -DLFS_NAME_MAX=64 -Ofast {build.debug_flags} "-I{build.core.path}/cmsis/include" "-I{nordic.path}" "-I{nordic.path}/nrfx" "-I{nordic.path}/nrfx/hal" "-I{nordic.path}/nrfx/mdk" "-I{nordic.path}/nrfx/soc" "-I{nordic.path}/nrfx/drivers/include" "-I{nordic.path}/nrfx/drivers/src" "-I{nordic.path}/softdevice/{build.sd_name}_nrf52_{build.sd_version}_API/include" "-I{rtos.path}/Source/include" "-I{rtos.path}/config" "-I{rtos.path}/portable/GCC/nrf52" "-I{rtos.path}/portable/CMSIS/nrf52" "-I{build.core.path}/sysview/SEGGER" "-I{build.core.path}/sysview/Config" "-I{build.core.path}/TinyUSB" "-I{build.core.path}/TinyUSB/Adafruit_TinyUSB_ArduinoCore" "-I{build.core.path}/TinyUSB/Adafruit_TinyUSB_ArduinoCore/tinyusb/src" +build.flags.nrf= -DSOFTDEVICE_PRESENT -DARDUINO_NRF52_ADAFRUIT -DNRF52_SERIES -DLFS_NAME_MAX=64 {build.debug_flags} "-I{build.core.path}/cmsis/include" "-I{nordic.path}" "-I{nordic.path}/nrfx" "-I{nordic.path}/nrfx/hal" "-I{nordic.path}/nrfx/mdk" "-I{nordic.path}/nrfx/soc" "-I{nordic.path}/nrfx/drivers/include" "-I{nordic.path}/nrfx/drivers/src" "-I{nordic.path}/softdevice/{build.sd_name}_nrf52_{build.sd_version}_API/include" "-I{rtos.path}/Source/include" "-I{rtos.path}/config" "-I{rtos.path}/portable/GCC/nrf52" "-I{rtos.path}/portable/CMSIS/nrf52" "-I{build.core.path}/sysview/SEGGER" "-I{build.core.path}/sysview/Config" "-I{build.core.path}/TinyUSB" "-I{build.core.path}/TinyUSB/Adafruit_TinyUSB_ArduinoCore" "-I{build.core.path}/TinyUSB/Adafruit_TinyUSB_ArduinoCore/tinyusb/src" # usb flags build.flags.usb= -DUSBCON -DUSE_TINYUSB -DUSB_VID={build.vid} -DUSB_PID={build.pid} '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}' @@ -88,7 +94,7 @@ recipe.S.o.pattern="{compiler.path}{compiler.S.cmd}" {compiler.S.flags} -DF_CPU= recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{archive_file_path}" "{object_file}" ## Combine gc-sections, archives, and objects -recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" "-L{build.path}" "-L{build.core.path}/linker" "-T{build.ldscript}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.ldflags} -o "{build.path}/{build.project_name}.elf" {object_files} {compiler.libraries.ldflags} -Wl,--start-group -lm "{build.path}/{archive_file}" -Wl,--end-group +recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" "-L{build.path}" "-L{build.core.path}/linker" "-T{build.ldscript}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.ldflags} -o "{build.path}/{build.project_name}.elf" {object_files} -Wl,--start-group -lm "{build.path}/{archive_file}" {compiler.libraries.ldflags} -Wl,--end-group ## Create output (bin file) #recipe.objcopy.bin.pattern="{compiler.path}{compiler.elf2bin.cmd}" {compiler.elf2bin.flags} {compiler.elf2bin.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.bin" From 2121a16d346f9292d945309403f3865a743157ca Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 12 Feb 2020 12:51:30 +0700 Subject: [PATCH 08/74] better support compiler.libraries.ldflags --- cores/nRF5/linker/nrf52840_s140_v6.ld | 2 +- platform.txt | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/cores/nRF5/linker/nrf52840_s140_v6.ld b/cores/nRF5/linker/nrf52840_s140_v6.ld index d676b6053..6dad975b0 100755 --- a/cores/nRF5/linker/nrf52840_s140_v6.ld +++ b/cores/nRF5/linker/nrf52840_s140_v6.ld @@ -7,7 +7,7 @@ MEMORY { FLASH (rx) : ORIGIN = 0x26000, LENGTH = 0xED000 - 0x26000 - /* SRAM required by S132 depend on + /* SRAM required by Softdevice depend on * - Attribute Table Size (Number of Services and Characteristics) * - Vendor UUID count * - Max ATT MTU diff --git a/platform.txt b/platform.txt index 57b3cdfbc..6224708ae 100644 --- a/platform.txt +++ b/platform.txt @@ -30,16 +30,16 @@ compiler.warning_flags.all=-Wall -Wextra -Wno-unused-parameter -Wno-missing-fiel compiler.path={runtime.tools.arm-none-eabi-gcc.path}/bin/ compiler.c.cmd=arm-none-eabi-gcc -compiler.c.flags=-mcpu={build.mcu} -mthumb -c -g {compiler.warning_flags} {build.float_flags} -std=gnu11 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -MMD -Ofast +compiler.c.flags=-mcpu={build.mcu} -mthumb -c -Ofast -g {compiler.warning_flags} {build.float_flags} -std=gnu11 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -MMD compiler.c.elf.cmd=arm-none-eabi-gcc -compiler.c.elf.flags=-Ofast -Wl,--gc-sections -save-temps +compiler.c.elf.flags=-Ofast -g -Wl,--gc-sections -save-temps compiler.S.cmd=arm-none-eabi-gcc -compiler.S.flags=-c -g -x assembler-with-cpp -Ofast +compiler.S.flags=-mcpu={build.mcu} -mthumb -mabi=aapcs -Ofast -g -c {build.float_flags} -x assembler-with-cpp compiler.cpp.cmd=arm-none-eabi-g++ -compiler.cpp.flags=-mcpu={build.mcu} -mthumb -c -g {compiler.warning_flags} {build.float_flags} -std=gnu++11 -ffunction-sections -fdata-sections -fno-threadsafe-statics -nostdlib --param max-inline-insns-single=500 -fno-rtti -fno-exceptions -MMD -Ofast +compiler.cpp.flags=-mcpu={build.mcu} -mthumb -c -Ofast -g {compiler.warning_flags} {build.float_flags} -std=gnu++11 -ffunction-sections -fdata-sections -fno-threadsafe-statics -nostdlib --param max-inline-insns-single=500 -fno-rtti -fno-exceptions -MMD compiler.ar.cmd=arm-none-eabi-ar compiler.ar.flags=rcs @@ -63,7 +63,7 @@ rtos.path={build.core.path}/freertos nordic.path={build.core.path}/nordic -build.flags.nrf= -DSOFTDEVICE_PRESENT -DARDUINO_NRF52_ADAFRUIT -DNRF52_SERIES -DLFS_NAME_MAX=64 {build.debug_flags} "-I{build.core.path}/cmsis/include" "-I{nordic.path}" "-I{nordic.path}/nrfx" "-I{nordic.path}/nrfx/hal" "-I{nordic.path}/nrfx/mdk" "-I{nordic.path}/nrfx/soc" "-I{nordic.path}/nrfx/drivers/include" "-I{nordic.path}/nrfx/drivers/src" "-I{nordic.path}/softdevice/{build.sd_name}_nrf52_{build.sd_version}_API/include" "-I{rtos.path}/Source/include" "-I{rtos.path}/config" "-I{rtos.path}/portable/GCC/nrf52" "-I{rtos.path}/portable/CMSIS/nrf52" "-I{build.core.path}/sysview/SEGGER" "-I{build.core.path}/sysview/Config" "-I{build.core.path}/TinyUSB" "-I{build.core.path}/TinyUSB/Adafruit_TinyUSB_ArduinoCore" "-I{build.core.path}/TinyUSB/Adafruit_TinyUSB_ArduinoCore/tinyusb/src" +build.flags.nrf= -DSOFTDEVICE_PRESENT -DARDUINO_NRF52_ADAFRUIT -DNRF52_SERIES -DDX_CC_TEE -DLFS_NAME_MAX=64 {build.debug_flags} "-I{build.core.path}/cmsis/include" "-I{nordic.path}" "-I{nordic.path}/nrfx" "-I{nordic.path}/nrfx/hal" "-I{nordic.path}/nrfx/mdk" "-I{nordic.path}/nrfx/soc" "-I{nordic.path}/nrfx/drivers/include" "-I{nordic.path}/nrfx/drivers/src" "-I{nordic.path}/softdevice/{build.sd_name}_nrf52_{build.sd_version}_API/include" "-I{rtos.path}/Source/include" "-I{rtos.path}/config" "-I{rtos.path}/portable/GCC/nrf52" "-I{rtos.path}/portable/CMSIS/nrf52" "-I{build.core.path}/sysview/SEGGER" "-I{build.core.path}/sysview/Config" "-I{build.core.path}/TinyUSB" "-I{build.core.path}/TinyUSB/Adafruit_TinyUSB_ArduinoCore" "-I{build.core.path}/TinyUSB/Adafruit_TinyUSB_ArduinoCore/tinyusb/src" # usb flags build.flags.usb= -DUSBCON -DUSE_TINYUSB -DUSB_VID={build.vid} -DUSB_PID={build.pid} '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}' @@ -76,6 +76,7 @@ compiler.S.extra_flags= compiler.ar.extra_flags= compiler.elf2bin.extra_flags= compiler.elf2hex.extra_flags= +compiler.libraries.ldflags= # Compile patterns From 157664702c410b80f81d47b56a31bb8edcf99463 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 13 Feb 2020 11:29:39 +0700 Subject: [PATCH 09/74] clean up --- cores/nRF5/verify.h | 4 ++-- libraries/Bluefruit52Lib/src/utility/bonding.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cores/nRF5/verify.h b/cores/nRF5/verify.h index b9114547b..c66cb4b35 100644 --- a/cores/nRF5/verify.h +++ b/cores/nRF5/verify.h @@ -61,13 +61,13 @@ extern "C" static inline void VERIFY_MESS_impl(int32_t _status, const char* (*_fstr)(int32_t), const char* func_name, int line_number) { printf("%s: %d: verify failed, error = ", func_name, line_number); - if (_fstr) + if (_fstr && _fstr(_status)) { printf(_fstr(_status)); } else { - printf("%ld", _status); + printf("0x%lX (%ld)", _status, _status); } printf("\n"); } diff --git a/libraries/Bluefruit52Lib/src/utility/bonding.cpp b/libraries/Bluefruit52Lib/src/utility/bonding.cpp index 9783ac5d2..a01b33638 100644 --- a/libraries/Bluefruit52Lib/src/utility/bonding.cpp +++ b/libraries/Bluefruit52Lib/src/utility/bonding.cpp @@ -53,9 +53,9 @@ using namespace Adafruit_LittleFS_Namespace; /*------------------------------------------------------------------*/ /* Bond Key is saved in following layout - * - Bond Data : 80 bytes - * - Name : variable (including null char) - * - CCCD : variable + * - Keyset : 80 bytes (sizeof(bond_keys_t)) + * - Name : variable (including null char) + * - CCCD : variable * * Each field has an 1-byte preceding length *------------------------------------------------------------------*/ From 6f03286dd9aa7d8a371349320c62575cca10a247 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 13 Feb 2020 11:30:34 +0700 Subject: [PATCH 10/74] add Adafruit nRFCrypto to depend library --- libraries/Bluefruit52Lib/library.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/Bluefruit52Lib/library.properties b/libraries/Bluefruit52Lib/library.properties index 208b34b28..86688d2e6 100644 --- a/libraries/Bluefruit52Lib/library.properties +++ b/libraries/Bluefruit52Lib/library.properties @@ -8,3 +8,4 @@ category=Communication url=https://github.com/adafruit/Adafruit_nRF52_Arduino architectures=* includes=bluefruit.h +depends=Adafruit nRFCrypto From 4402af2139be6cf52e719a3c167d43f09b358525 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 13 Feb 2020 16:09:36 +0700 Subject: [PATCH 11/74] getting passed the LESC DHKEY --- cores/nRF5/common_func.h | 7 +- .../pairing_display/pairing_display.ino | 2 + .../Bluefruit52Lib/src/BLEConnection.cpp | 64 +++++++++++++++--- libraries/Bluefruit52Lib/src/bluefruit.cpp | 67 +++++++++++++++++-- 4 files changed, 125 insertions(+), 15 deletions(-) diff --git a/cores/nRF5/common_func.h b/cores/nRF5/common_func.h index e29474950..745633305 100644 --- a/cores/nRF5/common_func.h +++ b/cores/nRF5/common_func.h @@ -157,8 +157,11 @@ const char* dbg_err_str(int32_t err_id); // TODO move to other place #define PRINT_BUFFER(buf, n) \ do {\ uint8_t const* p8 = (uint8_t const*) (buf);\ - PRINTF(#buf ": ");\ - for(uint32_t i=0; i<(n); i++) PRINTF("%02x ", p8[i]);\ + PRINTF(#buf ": \n");\ + for(uint32_t i=0; i<(n); i++) {\ + if (i%16 == 0) PRINTF("\n"); \ + PRINTF("%02x ", p8[i]); \ + }\ PRINTF("\n");\ }while(0) diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino index fc67c640c..8c11c3836 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino @@ -17,6 +17,7 @@ #include #include #include +#include /* This sketch demonstrates Pairing process using static Passkey aka PIN. * This sketch is essentially the same as bleuart.ino except the BLE Uart @@ -84,6 +85,7 @@ BLEUart bleuart; // uart over ble void setup() { Serial.begin(115200); + while(!Serial) delay(1); #if TFT_IN_USE == TFT_GIZMO tft.init(240, 240); diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.cpp b/libraries/Bluefruit52Lib/src/BLEConnection.cpp index 9f858aaac..fa25b3c26 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.cpp +++ b/libraries/Bluefruit52Lib/src/BLEConnection.cpp @@ -36,6 +36,20 @@ #include "bluefruit.h" + +#ifdef NRF_CRYPTOCELL +#include "Adafruit_nRFCrypto.h" + +extern nRFCrypto_ECC _ecpki; +extern nRFCrypto_ECC_PrivateKey _private_key; +extern nRFCrypto_ECC_PublicKey _public_key; + +extern uint8_t _lesc_public_rawkey[1+64]; // 1 byte for header +static ble_gap_lesc_p256_pk_t _lesc_peer_pubkey; + +extern void swap_key_endian(uint8_t rawkey[]); +#endif + //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM DECLARATION //--------------------------------------------------------------------+ @@ -304,10 +318,11 @@ void BLEConnection::_eventHandler(ble_evt_t* evt) //--------------------------------------------------------------------+ /* First-time Pairing + * BLE_GAP_EVT_LESC_DHKEY_REQUEST * Connect -> SEC_PARAMS_REQUEST -> PASSKEY_DISPLAY -> CONN_SEC_UPDATE -> AUTH_STATUS * 1. Either we or peer initiate the process * 2. Peer ask for Secure Parameter ( I/O Caps ) BLE_GAP_EVT_SEC_PARAMS_REQUEST - * 3. Pair Key exchange ( PIN code) + * 3. Pair PassKey exchange * 4. Connection is secured BLE_GAP_EVT_CONN_SEC_UPDATE * 5. Long term Keys exchanged BLE_GAP_EVT_AUTH_STATUS * @@ -342,23 +357,56 @@ void BLEConnection::_eventHandler(ble_evt_t* evt) .p_enc_key = &_bond_keys->own_enc, .p_id_key = NULL, .p_sign_key = NULL, - .p_pk = NULL + .p_pk = (ble_gap_lesc_p256_pk_t*) (_lesc_public_rawkey+1) }, .keys_peer = { .p_enc_key = &_bond_keys->peer_enc, .p_id_key = &_bond_keys->peer_id, .p_sign_key = NULL, - .p_pk = NULL + .p_pk = &_lesc_peer_pubkey } }; ble_gap_sec_params_t sec_param = Bluefruit.getSecureParam(); - VERIFY_STATUS(sd_ble_gap_sec_params_reply(_conn_hdl, - BLE_GAP_SEC_STATUS_SUCCESS, - _role == BLE_GAP_ROLE_PERIPH ? &sec_param : NULL, - &keyset), - ); + + // use LESC when both support it + if ( peer->lesc && sec_param.lesc ) + { +// keyset. + } + + VERIFY_STATUS(sd_ble_gap_sec_params_reply(_conn_hdl, BLE_GAP_SEC_STATUS_SUCCESS, + _role == BLE_GAP_ROLE_PERIPH ? &sec_param : NULL, &keyset), ); + } + break; + + case BLE_GAP_EVT_LESC_DHKEY_REQUEST: + { + ble_gap_evt_lesc_dhkey_request_t* dhkey_req = &evt->evt.gap_evt.params.lesc_dhkey_request; + + if ( dhkey_req->oobd_req ) + { + // Out of Band not supported yet + } + + uint8_t peer_raw_pubkey[64+1]; + ble_gap_lesc_dhkey_t dhkey; + + peer_raw_pubkey[0] = CRYS_EC_PointUncompressed; + memcpy(peer_raw_pubkey+1, dhkey_req->p_pk_peer->pk, 64); + + swap_key_endian(peer_raw_pubkey+1); + swap_key_endian(peer_raw_pubkey+1+32); + + nRFCrypto_ECC_PublicKey peer_pubkey; + peer_pubkey.begin(CRYS_ECPKI_DomainID_secp256r1); + peer_pubkey.fromRaw(peer_raw_pubkey, sizeof(peer_raw_pubkey)); + + nRFCrypto_ECC::SVDP_DH(_private_key, peer_pubkey, dhkey.key, sizeof(dhkey.key)); + swap_key_endian(dhkey.key); + + sd_ble_gap_lesc_dhkey_reply(_conn_hdl, &dhkey); } break; diff --git a/libraries/Bluefruit52Lib/src/bluefruit.cpp b/libraries/Bluefruit52Lib/src/bluefruit.cpp index 276692ba3..6cc5a779b 100644 --- a/libraries/Bluefruit52Lib/src/bluefruit.cpp +++ b/libraries/Bluefruit52Lib/src/bluefruit.cpp @@ -37,6 +37,32 @@ #include "bluefruit.h" #include "utility/bonding.h" +#ifdef NRF_CRYPTOCELL +#include "Adafruit_nRFCrypto.h" + +nRFCrypto_ECC _ecpki; +nRFCrypto_ECC_PrivateKey _private_key; +nRFCrypto_ECC_PublicKey _public_key; + +uint8_t _lesc_public_rawkey[1+64]; // 1 byte for header + +// convert 32-byte Number from Big <-> Little Endian to use with BLE +// Public Key = 32-byte N1 + 32-byte N2 +void swap_key_endian(uint8_t rawkey[]) +{ + for(uint8_t i=0; i<32/2; i++) + { + uint8_t const p1 = i; + uint8_t const p2 = (31-i); + + uint8_t temp = rawkey[p1]; + rawkey[p1] = rawkey[p2]; + rawkey[p2] = temp; + } +} + +#endif + #ifndef CFG_BLE_TX_POWER_LEVEL #define CFG_BLE_TX_POWER_LEVEL 0 #endif @@ -113,6 +139,8 @@ static void nrf_error_cb(uint32_t id, uint32_t pc, uint32_t info) { typedef struct { + // convert from Big to Little Endian to use with BLE + // Public Key = 32-byte N1 + 32-byte N2 uint16_t line_num; /**< The line number where the error occurred. */ uint8_t const * p_file_name; /**< The file in which the error occurred. */ } assert_info_t; @@ -176,6 +204,7 @@ AdafruitBluefruit::AdafruitBluefruit(void) _event_cb = NULL; _rssi_cb = NULL; _pair_display_cb = NULL; + _pair_complete_cb = NULL; _sec_param = ((ble_gap_sec_params_t) { @@ -190,6 +219,10 @@ AdafruitBluefruit::AdafruitBluefruit(void) .kdist_own = { .enc = 1, .id = 1}, .kdist_peer = { .enc = 1, .id = 1}, }); + +#ifdef NRF_CRYPTOCELL +// _sec_param.lesc = 1; // enable LESC if CryptoCell is present +#endif } void AdafruitBluefruit::configServiceChanged(bool changed) @@ -489,6 +522,26 @@ bool AdafruitBluefruit::begin(uint8_t prph_count, uint8_t central_count) // Initialize bonding bond_init(); + // Initalize Crypto lib for LESC +#ifdef NRF_CRYPTOCELL + nRFCrypto.begin(); + _ecpki.begin(); + + _private_key.begin(CRYS_ECPKI_DomainID_secp256r1); + _public_key.begin(CRYS_ECPKI_DomainID_secp256r1); + + nRFCrypto_ECC::genKeyPair(_private_key, _public_key); + + _public_key.toRaw(_lesc_public_rawkey, sizeof(_lesc_public_rawkey)); +// PRINT_BUFFER(_lesc_public_rawkey+1, sizeof(_lesc_public_rawkey)-1); + + // Public Key = 32-byte N1 + 32-byte N2 + swap_key_endian(_lesc_public_rawkey+1); + swap_key_endian(_lesc_public_rawkey+1+32); + +// PRINT_BUFFER(_lesc_public_rawkey+1, sizeof(_lesc_public_rawkey)-1); +#endif + return true; } @@ -662,7 +715,7 @@ bool AdafruitBluefruit::setPIN(const char* pin) { _sec_param.bond = 1; _sec_param.mitm = 0; - _sec_param.lesc = 0; + _sec_param.lesc = 0; // TODO NRF_CRYPTOCELL _sec_param.io_caps = BLE_GAP_IO_CAPS_NONE; }else { @@ -697,8 +750,12 @@ bool AdafruitBluefruit::setPairingDisplayCallback(pair_display_cb_t fp) { _sec_param.bond = 1; _sec_param.mitm = 1; - _sec_param.lesc = 0; - _sec_param.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY; + + // TODO NRF_CRYPTOCELL +// _sec_param.lesc = 0; +// _sec_param.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY; + _sec_param.lesc = 1; + _sec_param.io_caps = BLE_GAP_IO_CAPS_NONE; ble_opt_t opt; opt.gap_opt.passkey.p_passkey = NULL; // generate Passkey randomly @@ -716,7 +773,7 @@ void AdafruitBluefruit::setPairingCompleteCallback(pair_complete_cb_t fp) /*------------------------------------------------------------------*/ /* Thread & SoftDevice Event handler *------------------------------------------------------------------*/ -void SD_EVT_IRQHandler(void) +extern "C" void SD_EVT_IRQHandler(void) { // Notify both BLE & SOC Task xSemaphoreGiveFromISR(Bluefruit._soc_event_sem, NULL); @@ -1038,7 +1095,7 @@ void Bluefruit_printInfo(void) void AdafruitBluefruit::printInfo(void) { - // Skip if Serial is not initialised + // Skip if Serial is not initialized if ( !Serial ) return; // Skip if Bluefruit.begin() is not called From 844e5cae233381fbaaf81494e7892dee3909fae3 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 13 Feb 2020 17:43:11 +0700 Subject: [PATCH 12/74] save peer LTK (bond) if it is distributed --- .../Bluefruit52Lib/src/BLEConnection.cpp | 47 +++++++++++-------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.cpp b/libraries/Bluefruit52Lib/src/BLEConnection.cpp index fa25b3c26..ddbbb3878 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.cpp +++ b/libraries/Bluefruit52Lib/src/BLEConnection.cpp @@ -318,8 +318,9 @@ void BLEConnection::_eventHandler(ble_evt_t* evt) //--------------------------------------------------------------------+ /* First-time Pairing - * BLE_GAP_EVT_LESC_DHKEY_REQUEST - * Connect -> SEC_PARAMS_REQUEST -> PASSKEY_DISPLAY -> CONN_SEC_UPDATE -> AUTH_STATUS + * + * Connect -> SEC_PARAMS_REQUEST -> PASSKEY_DISPLAY -> BLE_GAP_EVT_LESC_DHKEY_REQUEST -> + * CONN_SEC_UPDATE -> AUTH_STATUS * 1. Either we or peer initiate the process * 2. Peer ask for Secure Parameter ( I/O Caps ) BLE_GAP_EVT_SEC_PARAMS_REQUEST * 3. Pair PassKey exchange @@ -381,6 +382,21 @@ void BLEConnection::_eventHandler(ble_evt_t* evt) } break; + // case BLE_GAP_EVT_PASSKEY_DISPLAY: +// { +// ble_gap_evt_passkey_display_t const* passkey_display = &evt->evt.gap_evt.params.passkey_display; +// LOG_LV2("PAIR", "Passkey = %.6s, match request = %d", passkey_display->passkey, passkey_display->match_request); +// +// if ( Bluefruit._pair_display_cb ) ada_callback(passkey_display->passkey, 6, ) +// +// if (passkey_display->match_request) +// { +// // Match request require to report the match +// // sd_ble_gap_auth_key_reply(); +// } +// } +// break; + case BLE_GAP_EVT_LESC_DHKEY_REQUEST: { ble_gap_evt_lesc_dhkey_request_t* dhkey_req = &evt->evt.gap_evt.params.lesc_dhkey_request; @@ -415,15 +431,20 @@ void BLEConnection::_eventHandler(ble_evt_t* evt) // Pairing process completed ble_gap_evt_auth_status_t* status = &evt->evt.gap_evt.params.auth_status; - LOG_LV2("PAIR", "Auth Status = 0x%02x (BLE_GAP_SEC_STATUS)", status->auth_status); + LOG_LV2("PAIR", "Auth Status = 0x%02X, Bonded = %d, LESC = %d, Our Kdist = 0x%02X, Peer Kdist = 0x%02X ", + status->auth_status, status->bonded, status->lesc, *((uint8_t*) &status->kdist_own), *((uint8_t*) &status->kdist_peer)); // Pairing succeeded --> save encryption keys ( Bonding ) if (BLE_GAP_SEC_STATUS_SUCCESS == status->auth_status) { _paired = true; - _ediv = _bond_keys->own_enc.master_id.ediv; - bond_save_keys(_role, _conn_hdl, _bond_keys); + // Save LTK if peer distribute to us + if ( status->kdist_peer.enc ) + { + _ediv = _bond_keys->own_enc.master_id.ediv; + bond_save_keys(_role, _conn_hdl, _bond_keys); + } } rtos_free(_bond_keys); @@ -453,24 +474,10 @@ void BLEConnection::_eventHandler(ble_evt_t* evt) } break; -// case BLE_GAP_EVT_PASSKEY_DISPLAY: -// { -// ble_gap_evt_passkey_display_t const* passkey_display = &evt->evt.gap_evt.params.passkey_display; -// LOG_LV2("PAIR", "Passkey = %.6s, match request = %d", passkey_display->passkey, passkey_display->match_request); -// -// if ( Bluefruit._pair_display_cb ) ada_callback(passkey_display->passkey, 6, ) -// -// if (passkey_display->match_request) -// { -// // Match request require to report the match -// // sd_ble_gap_auth_key_reply(); -// } -// } -// break; - case BLE_GAP_EVT_CONN_SEC_UPDATE: { const ble_gap_conn_sec_t* conn_sec = &evt->evt.gap_evt.params.conn_sec_update.conn_sec; + LOG_LV2("PAIR", "Security Mode = %d, Level = %d", conn_sec->sec_mode.sm, conn_sec->sec_mode.lv); // Connection is secured (paired) if encryption level > 1 if ( !( conn_sec->sec_mode.sm == 1 && conn_sec->sec_mode.lv == 1) ) From 5b1eeab9567f3475f2775c4965a7884b51f9e3a5 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 13 Feb 2020 18:54:38 +0700 Subject: [PATCH 13/74] LESC passkey pairing work well --- libraries/Bluefruit52Lib/src/BLEConnection.cpp | 8 ++------ libraries/Bluefruit52Lib/src/bluefruit.cpp | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.cpp b/libraries/Bluefruit52Lib/src/BLEConnection.cpp index ddbbb3878..5843b56ee 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.cpp +++ b/libraries/Bluefruit52Lib/src/BLEConnection.cpp @@ -439,12 +439,8 @@ void BLEConnection::_eventHandler(ble_evt_t* evt) { _paired = true; - // Save LTK if peer distribute to us - if ( status->kdist_peer.enc ) - { - _ediv = _bond_keys->own_enc.master_id.ediv; - bond_save_keys(_role, _conn_hdl, _bond_keys); - } + _ediv = _bond_keys->own_enc.master_id.ediv; + bond_save_keys(_role, _conn_hdl, _bond_keys); } rtos_free(_bond_keys); diff --git a/libraries/Bluefruit52Lib/src/bluefruit.cpp b/libraries/Bluefruit52Lib/src/bluefruit.cpp index 6cc5a779b..c78870d02 100644 --- a/libraries/Bluefruit52Lib/src/bluefruit.cpp +++ b/libraries/Bluefruit52Lib/src/bluefruit.cpp @@ -755,7 +755,7 @@ bool AdafruitBluefruit::setPairingDisplayCallback(pair_display_cb_t fp) // _sec_param.lesc = 0; // _sec_param.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY; _sec_param.lesc = 1; - _sec_param.io_caps = BLE_GAP_IO_CAPS_NONE; + _sec_param.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY; ble_opt_t opt; opt.gap_opt.passkey.p_passkey = NULL; // generate Passkey randomly From 53c9580f713d0a435db3262e63f5522b8f5ccf2c Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 14 Feb 2020 12:36:46 +0700 Subject: [PATCH 14/74] Introducing BLEPairing class move all pairing/bonding related to BLEPairing --- cores/nRF5/common_func.h | 36 +- cores/nRF5/rtos.h | 10 +- .../pairing_display/pairing_display.ino | 4 +- .../Peripheral/pairing_pin/pairing_pin.ino | 2 +- .../Bluefruit52Lib/src/BLEConnection.cpp | 154 +------- libraries/Bluefruit52Lib/src/BLEPairing.cpp | 359 ++++++++++++++++++ libraries/Bluefruit52Lib/src/BLEPairing.h | 75 ++++ libraries/Bluefruit52Lib/src/bluefruit.cpp | 157 +------- libraries/Bluefruit52Lib/src/bluefruit.h | 16 +- 9 files changed, 478 insertions(+), 335 deletions(-) create mode 100644 libraries/Bluefruit52Lib/src/BLEPairing.cpp create mode 100644 libraries/Bluefruit52Lib/src/BLEPairing.h diff --git a/cores/nRF5/common_func.h b/cores/nRF5/common_func.h index 745633305..27be23eee 100644 --- a/cores/nRF5/common_func.h +++ b/cores/nRF5/common_func.h @@ -117,27 +117,27 @@ const char* dbg_err_str(int32_t err_id); // TODO move to other place #if CFG_DEBUG -#define LOG_LV1(...) ADALOG(__VA_ARGS__) -#define LOG_LV1_BUFFER(...) ADALOG_BUFFER(__VA_ARGS__) + #define LOG_LV1(...) ADALOG(__VA_ARGS__) + #define LOG_LV1_BUFFER(...) ADALOG_BUFFER(__VA_ARGS__) #else -#define LOG_LV1(...) -#define LOG_LV1_BUFFER(...) + #define LOG_LV1(...) + #define LOG_LV1_BUFFER(...) #endif #if CFG_DEBUG >= 2 -#define LOG_LV2(...) ADALOG(__VA_ARGS__) -#define LOG_LV2_BUFFER(...) ADALOG_BUFFER(__VA_ARGS__) + #define LOG_LV2(...) ADALOG(__VA_ARGS__) + #define LOG_LV2_BUFFER(...) ADALOG_BUFFER(__VA_ARGS__) #else -#define LOG_LV2(...) -#define LOG_LV2_BUFFER(...) + #define LOG_LV2(...) + #define LOG_LV2_BUFFER(...) #endif #if CFG_DEBUG #if __cplusplus -#define PRINTF ::printf + #define PRINTF ::printf #else -#define PRINTF printf + #define PRINTF printf #endif #define PRINT_LOCATION() PRINTF("%s: %d:\n", __PRETTY_FUNCTION__, __LINE__) @@ -181,14 +181,14 @@ const char* dbg_err_str(int32_t err_id); // TODO move to other place #else -#define PRINT_LOCATION() -#define PRINT_MESS(x) -#define PRTNT_HEAP() -#define PRINT_STR(x) -#define PRINT_INT(x) -#define PRINT_HEX(x) -#define PRINT_BUFFER(buf, n) -#define ADALOG(...) + #define PRINT_LOCATION() + #define PRINT_MESS(x) + #define PRTNT_HEAP() + #define PRINT_STR(x) + #define PRINT_INT(x) + #define PRINT_HEX(x) + #define PRINT_BUFFER(buf, n) + #define ADALOG(...) #endif diff --git a/cores/nRF5/rtos.h b/cores/nRF5/rtos.h index 86e7b0b29..e193c1430 100644 --- a/cores/nRF5/rtos.h +++ b/cores/nRF5/rtos.h @@ -50,7 +50,10 @@ #include "queue.h" #include "semphr.h" +#define DEBUG_MALLOC 1 + #define DELAY_FOREVER portMAX_DELAY + enum { TASK_PRIO_LOWEST = 0, // Idle task, should not be used @@ -65,8 +68,11 @@ enum #define tick2ms(tck) ( ( ((uint64_t)(tck)) * 1000) / configTICK_RATE_HZ ) #define tick2us(tck) ( ( ((uint64_t)(tck)) * 1000000) / configTICK_RATE_HZ ) -#define malloc_type(type) rtos_malloc( sizeof(type) ) -#define rtos_malloc_type(_type) (_type*) rtos_malloc(sizeof(_type)) +#if DEBUG_MALLOC + #define rtos_malloc_type(_type) ({ LOG_LV2("MALLOC", #_type " = %d bytes", sizeof(_type)); ((_type*) rtos_malloc(sizeof(_type))); }) +#else + #define rtos_malloc_type(_type) ((_type*) rtos_malloc(sizeof(_type))) +#endif static inline void* rtos_malloc(size_t _size) { diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino index 8c11c3836..cd9279faa 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino @@ -116,8 +116,8 @@ void setup() Bluefruit.setName("Bluefruit52"); // Serial.println("Setting pairing PIN to: " PAIRING_PIN); - Bluefruit.setPairingDisplayCallback(pairing_display_callback); - Bluefruit.setPairingCompleteCallback(pairing_complete_callback); + Bluefruit.Pairing.setDisplayCallback(pairing_display_callback); + Bluefruit.Pairing.setCompleteCallback(pairing_complete_callback); Bluefruit.Periph.setConnectCallback(connect_callback); Bluefruit.Periph.setDisconnectCallback(disconnect_callback); diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_pin/pairing_pin.ino b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_pin/pairing_pin.ino index 8e914c054..b92cd0d26 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_pin/pairing_pin.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_pin/pairing_pin.ino @@ -51,7 +51,7 @@ void setup() Bluefruit.setName("Bluefruit52"); Serial.println("Setting pairing PIN to: " PAIRING_PIN); - Bluefruit.setPIN(PAIRING_PIN); + Bluefruit.Pairing.setPIN(PAIRING_PIN); Bluefruit.Periph.setConnectCallback(connect_callback); Bluefruit.Periph.setDisconnectCallback(disconnect_callback); diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.cpp b/libraries/Bluefruit52Lib/src/BLEConnection.cpp index 5843b56ee..738cfd986 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.cpp +++ b/libraries/Bluefruit52Lib/src/BLEConnection.cpp @@ -36,20 +36,6 @@ #include "bluefruit.h" - -#ifdef NRF_CRYPTOCELL -#include "Adafruit_nRFCrypto.h" - -extern nRFCrypto_ECC _ecpki; -extern nRFCrypto_ECC_PrivateKey _private_key; -extern nRFCrypto_ECC_PublicKey _public_key; - -extern uint8_t _lesc_public_rawkey[1+64]; // 1 byte for header -static ble_gap_lesc_p256_pk_t _lesc_peer_pubkey; - -extern void swap_key_endian(uint8_t rawkey[]); -#endif - //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM DECLARATION //--------------------------------------------------------------------+ @@ -73,8 +59,6 @@ BLEConnection::BLEConnection(uint16_t conn_hdl, ble_gap_evt_connected_t const* e _hvc_sem = NULL; _hvc_received = false; _pair_sem = NULL; - _ediv = 0xFFFF; // invalid ediv value - _bond_keys = NULL; } BLEConnection::~BLEConnection() @@ -334,157 +318,23 @@ void BLEConnection::_eventHandler(ble_evt_t* evt) * 3. Connection is secured BLE_GAP_EVT_CONN_SEC_UPDATE */ //--------------------------------------------------------------------+ - case BLE_GAP_EVT_SEC_PARAMS_REQUEST: - { - // Pairing in progress, Peer asking for our info - _bond_keys = (bond_keys_t*) rtos_malloc( sizeof(bond_keys_t)); - VERIFY(_bond_keys, ); - memclr(_bond_keys, sizeof(bond_keys_t)); - - _ediv = 0xFFFF; // invalid value for ediv - - /* Step 1: Pairing/Bonding - * - Central supplies its parameters - * - We replies with our security parameters - */ - ble_gap_sec_params_t const* peer = &evt->evt.gap_evt.params.sec_params_request.peer_params; - (void) peer; - LOG_LV2("PAIR", "Peer Params: bond = %d, mitm = %d, lesc = %d, io_caps = %d", - peer->bond, peer->mitm, peer->lesc, peer->io_caps); - - ble_gap_sec_keyset_t keyset = - { - .keys_own = { - .p_enc_key = &_bond_keys->own_enc, - .p_id_key = NULL, - .p_sign_key = NULL, - .p_pk = (ble_gap_lesc_p256_pk_t*) (_lesc_public_rawkey+1) - }, - - .keys_peer = { - .p_enc_key = &_bond_keys->peer_enc, - .p_id_key = &_bond_keys->peer_id, - .p_sign_key = NULL, - .p_pk = &_lesc_peer_pubkey - } - }; - - ble_gap_sec_params_t sec_param = Bluefruit.getSecureParam(); - - // use LESC when both support it - if ( peer->lesc && sec_param.lesc ) - { -// keyset. - } - - VERIFY_STATUS(sd_ble_gap_sec_params_reply(_conn_hdl, BLE_GAP_SEC_STATUS_SUCCESS, - _role == BLE_GAP_ROLE_PERIPH ? &sec_param : NULL, &keyset), ); - } - break; - - // case BLE_GAP_EVT_PASSKEY_DISPLAY: -// { -// ble_gap_evt_passkey_display_t const* passkey_display = &evt->evt.gap_evt.params.passkey_display; -// LOG_LV2("PAIR", "Passkey = %.6s, match request = %d", passkey_display->passkey, passkey_display->match_request); -// -// if ( Bluefruit._pair_display_cb ) ada_callback(passkey_display->passkey, 6, ) -// -// if (passkey_display->match_request) -// { -// // Match request require to report the match -// // sd_ble_gap_auth_key_reply(); -// } -// } -// break; - - case BLE_GAP_EVT_LESC_DHKEY_REQUEST: - { - ble_gap_evt_lesc_dhkey_request_t* dhkey_req = &evt->evt.gap_evt.params.lesc_dhkey_request; - - if ( dhkey_req->oobd_req ) - { - // Out of Band not supported yet - } - - uint8_t peer_raw_pubkey[64+1]; - ble_gap_lesc_dhkey_t dhkey; - - peer_raw_pubkey[0] = CRYS_EC_PointUncompressed; - memcpy(peer_raw_pubkey+1, dhkey_req->p_pk_peer->pk, 64); - - swap_key_endian(peer_raw_pubkey+1); - swap_key_endian(peer_raw_pubkey+1+32); - - nRFCrypto_ECC_PublicKey peer_pubkey; - peer_pubkey.begin(CRYS_ECPKI_DomainID_secp256r1); - peer_pubkey.fromRaw(peer_raw_pubkey, sizeof(peer_raw_pubkey)); - - nRFCrypto_ECC::SVDP_DH(_private_key, peer_pubkey, dhkey.key, sizeof(dhkey.key)); - swap_key_endian(dhkey.key); - - sd_ble_gap_lesc_dhkey_reply(_conn_hdl, &dhkey); - } - break; case BLE_GAP_EVT_AUTH_STATUS: { - // Pairing process completed ble_gap_evt_auth_status_t* status = &evt->evt.gap_evt.params.auth_status; - LOG_LV2("PAIR", "Auth Status = 0x%02X, Bonded = %d, LESC = %d, Our Kdist = 0x%02X, Peer Kdist = 0x%02X ", - status->auth_status, status->bonded, status->lesc, *((uint8_t*) &status->kdist_own), *((uint8_t*) &status->kdist_peer)); - - // Pairing succeeded --> save encryption keys ( Bonding ) - if (BLE_GAP_SEC_STATUS_SUCCESS == status->auth_status) - { - _paired = true; - - _ediv = _bond_keys->own_enc.master_id.ediv; - bond_save_keys(_role, _conn_hdl, _bond_keys); - } - - rtos_free(_bond_keys); - _bond_keys = NULL; - } - break; - - case BLE_GAP_EVT_SEC_INFO_REQUEST: - { - // Peer asks for the stored keys. - // - load key and return if bonded previously. - // - Else return NULL --> Initiate key exchange - ble_gap_evt_sec_info_request_t* sec_req = (ble_gap_evt_sec_info_request_t*) &evt->evt.gap_evt.params.sec_info_request; - - bond_keys_t bkeys; - varclr(&bkeys); - - if ( bond_load_keys(_role, sec_req->master_id.ediv, &bkeys) ) - { - sd_ble_gap_sec_info_reply(_conn_hdl, &bkeys.own_enc.enc_info, &bkeys.peer_id.id_info, NULL); - - _ediv = bkeys.own_enc.master_id.ediv; - } else - { - sd_ble_gap_sec_info_reply(_conn_hdl, NULL, NULL, NULL); - } + // Pairing succeeded + if (BLE_GAP_SEC_STATUS_SUCCESS == status->auth_status) _paired = true; } break; case BLE_GAP_EVT_CONN_SEC_UPDATE: { const ble_gap_conn_sec_t* conn_sec = &evt->evt.gap_evt.params.conn_sec_update.conn_sec; - LOG_LV2("PAIR", "Security Mode = %d, Level = %d", conn_sec->sec_mode.sm, conn_sec->sec_mode.lv); // Connection is secured (paired) if encryption level > 1 if ( !( conn_sec->sec_mode.sm == 1 && conn_sec->sec_mode.lv == 1) ) { - // Previously bonded --> secure by re-connection process --> Load & Set SysAttr (Apply Service Context) - // Else Init SysAttr (first bonded) - if ( !bond_load_cccd(_role, _conn_hdl, _ediv) ) - { - sd_ble_gatts_sys_attr_set(_conn_hdl, NULL, 0, 0); - } - _paired = true; } diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.cpp b/libraries/Bluefruit52Lib/src/BLEPairing.cpp new file mode 100644 index 000000000..762030d18 --- /dev/null +++ b/libraries/Bluefruit52Lib/src/BLEPairing.cpp @@ -0,0 +1,359 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Ha Thach (tinyusb.org) for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "bluefruit.h" + +//--------------------------------------------------------------------+ +// MACRO TYPEDEF CONSTANT ENUM DECLARATION +//--------------------------------------------------------------------+ +#define EDIV_INVALID 0xFFFF + +//------------- IMPLEMENTATION -------------// + +// convert 32-byte Number from Big <-> Little Endian to use with BLE +// Public Key = 32-byte N1 + 32-byte N2 +void swap_key_endian(uint8_t rawkey[]) +{ + for(uint8_t i=0; i<32/2; i++) + { + uint8_t const p1 = i; + uint8_t const p2 = (31-i); + + uint8_t temp = rawkey[p1]; + rawkey[p1] = rawkey[p2]; + rawkey[p2] = temp; + } +} + +BLEPairing::BLEPairing(void) +{ + _sec_param = ((ble_gap_sec_params_t) + { + .bond = 1, + .mitm = 0, + .lesc = 0, + .keypress = 0, + .io_caps = BLE_GAP_IO_CAPS_NONE, + .oob = 0, + .min_key_size = 7, + .max_key_size = 16, + .kdist_own = { .enc = 1, .id = 1}, + .kdist_peer = { .enc = 1, .id = 1}, + }); + + _ediv = EDIV_INVALID; + _bond_keys = NULL; + + _display_cb = NULL; + _complete_cb = NULL; +} + +bool BLEPairing::begin(void) +{ + +#ifdef NRF_CRYPTOCELL + // Initalize Crypto lib for LESC (safe to call multiple times) + nRFCrypto.begin(); + + // Init Private key + _private_key.begin(CRYS_ECPKI_DomainID_secp256r1); + + // init public key + nRFCrypto_ECC_PublicKey pubkey; + pubkey.begin(CRYS_ECPKI_DomainID_secp256r1); + + // Generate ECC Key pair + nRFCrypto_ECC::genKeyPair(_private_key, pubkey); + + // Convert to Raw bytes to response to LESC event + pubkey.toRaw(_public_key_raw, sizeof(_public_key_raw)); + pubkey.end(); + + // BLE use Little Endian, swap public key endian + // Public Key = 32-byte N1 + 32-byte N2 + swap_key_endian(_public_key_raw+1); + swap_key_endian(_public_key_raw+1+32); +#endif + + return true; +} + +uint8_t* BLEPairing::getPublicKey(void) +{ + // skip header byte + return _public_key_raw+1; +} + +// Use Legacy SC static Passkey +bool BLEPairing::setPIN(const char* pin) +{ + // back to open mode + if (pin == NULL) + { + _sec_param.bond = 1; + _sec_param.mitm = 0; + _sec_param.lesc = 0; // TODO NRF_CRYPTOCELL + _sec_param.io_caps = BLE_GAP_IO_CAPS_NONE; + }else + { + VERIFY ( strlen(pin) == BLE_GAP_PASSKEY_LEN ); + + // Static Passkey requires using + // - Legacy SC + // - IO cap: Display + // - MITM is on + _sec_param.bond = 1; + _sec_param.mitm = 1; + _sec_param.lesc = 0; + _sec_param.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY; + + ble_opt_t opt; + opt.gap_opt.passkey.p_passkey = (const uint8_t*) pin; + VERIFY_STATUS( sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &opt), false); + } + + return true; +} + +// Pairing using LESC with peripheral display +bool BLEPairing::setDisplayCallback(pair_display_cb_t fp) +{ + _display_cb = fp; + + if ( fp == NULL ) + { + // TODO callback clear + }else + { + _sec_param.bond = 1; + _sec_param.mitm = 1; + + // TODO NRF_CRYPTOCELL +// _sec_param.lesc = 0; +// _sec_param.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY; + _sec_param.lesc = 1; + _sec_param.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY; + + ble_opt_t opt; + opt.gap_opt.passkey.p_passkey = NULL; // generate Passkey randomly + VERIFY_STATUS( sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &opt), false); + } + + return true; +} + +void BLEPairing::setCompleteCallback(pair_complete_cb_t fp) +{ + _complete_cb = fp; +} + +//--------------------------------------------------------------------+ +/* First-time Pairing + * + * Connect -> SEC_PARAMS_REQUEST -> PASSKEY_DISPLAY -> BLE_GAP_EVT_LESC_DHKEY_REQUEST -> + * CONN_SEC_UPDATE -> AUTH_STATUS + * 1. Either we or peer initiate the process + * 2. Peer ask for Secure Parameter ( I/O Caps ) BLE_GAP_EVT_SEC_PARAMS_REQUEST + * 3. Pair PassKey exchange + * 4. Connection is secured BLE_GAP_EVT_CONN_SEC_UPDATE + * 5. Long term Keys exchanged BLE_GAP_EVT_AUTH_STATUS + * + * Reconnect using bonded key + * Connect -> SEC_INFO_REQUEST -> CONN_SEC_UPDATE + * 1. Either we or peer initiate the process + * 2. Peer ask for Secure Info ( bond keys ) BLE_GAP_EVT_SEC_INFO_REQUEST + * 3. Connection is secured BLE_GAP_EVT_CONN_SEC_UPDATE + */ +//--------------------------------------------------------------------+ +void BLEPairing::_eventHandler(ble_evt_t* evt) +{ + uint16_t const conn_hdl = evt->evt.common_evt.conn_handle; + BLEConnection* conn = Bluefruit.Connection(conn_hdl); + + switch(evt->header.evt_id) + { + case BLE_GAP_EVT_SEC_PARAMS_REQUEST: + { + // Pairing in progress, Peer asking for our info + _bond_keys = rtos_malloc_type(bond_keys_t); + VERIFY(_bond_keys, ); + memclr(_bond_keys, sizeof(bond_keys_t)); + + _ediv = EDIV_INVALID; + + /* Step 1: Pairing/Bonding + * - Central supplies its parameters + * - We replies with our security parameters + */ + ble_gap_sec_params_t const* peer = &evt->evt.gap_evt.params.sec_params_request.peer_params; + (void) peer; + LOG_LV2("PAIR", "Peer Params: bond = %d, mitm = %d, lesc = %d, io_caps = %d", + peer->bond, peer->mitm, peer->lesc, peer->io_caps); + + ble_gap_sec_keyset_t keyset = + { + .keys_own = { + .p_enc_key = &_bond_keys->own_enc, + .p_id_key = NULL, + .p_sign_key = NULL, + .p_pk = (ble_gap_lesc_p256_pk_t*) (_public_key_raw+1) + }, + + .keys_peer = { + .p_enc_key = &_bond_keys->peer_enc, + .p_id_key = &_bond_keys->peer_id, + .p_sign_key = NULL, + .p_pk = (ble_gap_lesc_p256_pk_t*) (_peer_pubkey_raw+1) + } + }; + + // use LESC when both support it + if ( peer->lesc && _sec_param.lesc ) + { +// keyset. + } + + VERIFY_STATUS(sd_ble_gap_sec_params_reply(conn_hdl, BLE_GAP_SEC_STATUS_SUCCESS, + conn->getRole() == BLE_GAP_ROLE_PERIPH ? &_sec_param : NULL, &keyset), ); + } + break; + + case BLE_GAP_EVT_PASSKEY_DISPLAY: + { + ble_gap_evt_passkey_display_t const* passkey_display = &evt->evt.gap_evt.params.passkey_display; + LOG_LV2("PAIR", "Passkey = %.6s, match request = %d", passkey_display->passkey, passkey_display->match_request); + + // Invoke display callback + if ( _display_cb ) ada_callback(passkey_display->passkey, 6, _display_cb, conn_hdl, passkey_display->passkey); + + if (passkey_display->match_request) + { + // Match request require to report the match + // sd_ble_gap_auth_key_reply(); + } + } + break; + + case BLE_GAP_EVT_LESC_DHKEY_REQUEST: + { + ble_gap_evt_lesc_dhkey_request_t* dhkey_req = &evt->evt.gap_evt.params.lesc_dhkey_request; + + if ( dhkey_req->oobd_req ) + { + // Out of Band not supported yet + } + + uint8_t peer_raw_pubkey[64+1]; + ble_gap_lesc_dhkey_t dhkey; + + peer_raw_pubkey[0] = CRYS_EC_PointUncompressed; + memcpy(peer_raw_pubkey+1, dhkey_req->p_pk_peer->pk, 64); + + swap_key_endian(peer_raw_pubkey+1); + swap_key_endian(peer_raw_pubkey+1+32); + + nRFCrypto_ECC_PublicKey peer_pubkey; + peer_pubkey.begin(CRYS_ECPKI_DomainID_secp256r1); + peer_pubkey.fromRaw(peer_raw_pubkey, sizeof(peer_raw_pubkey)); + + nRFCrypto_ECC::SVDP_DH(_private_key, peer_pubkey, dhkey.key, sizeof(dhkey.key)); + swap_key_endian(dhkey.key); + + sd_ble_gap_lesc_dhkey_reply(conn_hdl, &dhkey); + } + break; + + // Pairing process completed + case BLE_GAP_EVT_AUTH_STATUS: + { + ble_gap_evt_auth_status_t* status = &evt->evt.gap_evt.params.auth_status; + + LOG_LV2("PAIR", "Auth Status = 0x%02X, Bonded = %d, LESC = %d, Our Kdist = 0x%02X, Peer Kdist = 0x%02X ", + status->auth_status, status->bonded, status->lesc, *((uint8_t*) &status->kdist_own), *((uint8_t*) &status->kdist_peer)); + + // Pairing succeeded --> save encryption keys ( Bonding ) + if (BLE_GAP_SEC_STATUS_SUCCESS == status->auth_status) + { + _ediv = _bond_keys->own_enc.master_id.ediv; + bond_save_keys(conn->getRole(), conn_hdl, _bond_keys); + +// _paired = true; + } + + rtos_free(_bond_keys); + _bond_keys = NULL; + + // Invoke callback + if (_complete_cb) ada_callback(NULL, 0, _complete_cb, conn_hdl, status->auth_status); + } + break; + + case BLE_GAP_EVT_SEC_INFO_REQUEST: + { + // Peer asks for the stored keys. + // - load key and return if bonded previously. + // - Else return NULL --> Initiate key exchange + ble_gap_evt_sec_info_request_t* sec_req = (ble_gap_evt_sec_info_request_t*) &evt->evt.gap_evt.params.sec_info_request; + + bond_keys_t bkeys; + varclr(&bkeys); + + if ( bond_load_keys(conn->getRole(), sec_req->master_id.ediv, &bkeys) ) + { + sd_ble_gap_sec_info_reply(conn_hdl, &bkeys.own_enc.enc_info, &bkeys.peer_id.id_info, NULL); + + _ediv = bkeys.own_enc.master_id.ediv; + } else + { + sd_ble_gap_sec_info_reply(conn_hdl, NULL, NULL, NULL); + } + } + break; + + case BLE_GAP_EVT_CONN_SEC_UPDATE: + { + const ble_gap_conn_sec_t* conn_sec = &evt->evt.gap_evt.params.conn_sec_update.conn_sec; + LOG_LV2("PAIR", "Security Mode = %d, Level = %d", conn_sec->sec_mode.sm, conn_sec->sec_mode.lv); + + // Connection is secured (paired) if encryption level > 1 + if ( !( conn_sec->sec_mode.sm == 1 && conn_sec->sec_mode.lv == 1) ) + { + // Previously bonded --> secure by re-connection process --> Load & Set SysAttr (Apply Service Context) + // Else Init SysAttr (first bonded) + if ( !bond_load_cccd(conn->getRole(), conn_hdl, _ediv) ) + { + sd_ble_gatts_sys_attr_set(conn_hdl, NULL, 0, 0); + } + +// _paired = true; + } + +// if (_pair_sem) xSemaphoreGive(_pair_sem); + } + break; + + + default: break; + } +} diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.h b/libraries/Bluefruit52Lib/src/BLEPairing.h new file mode 100644 index 000000000..028a52f20 --- /dev/null +++ b/libraries/Bluefruit52Lib/src/BLEPairing.h @@ -0,0 +1,75 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Ha Thach (tinyusb.org) for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef BLEPAIRING_H_ +#define BLEPAIRING_H_ + +#include "bluefruit_common.h" +#include "utility/bonding.h" + +#ifdef NRF_CRYPTOCELL +#include "Adafruit_nRFCrypto.h" +#endif + +class BLEPairing +{ + public: + typedef void (*pair_display_cb_t ) (uint16_t conn_hdl, uint8_t const passkey[6]); + typedef void (*pair_complete_cb_t) (uint16_t conn_hdl, uint8_t auth_status); + + BLEPairing(void); + + bool begin(void); + uint8_t* getPublicKey(void); + + // Static Passkey + bool setPIN(const char* pin); + + //------------- Callbacks -------------// + bool setDisplayCallback(pair_display_cb_t fp); + void setCompleteCallback(pair_complete_cb_t fp); + + /*------------------------------------------------------------------*/ + /* INTERNAL USAGE ONLY + * Although declare as public, it is meant to be invoked by internal + * code. User should not call these directly + *------------------------------------------------------------------*/ + void _eventHandler(ble_evt_t* evt); + + private: + ble_gap_sec_params_t _sec_param; + + uint8_t _public_key_raw[1+64]; // raw key: 1 header + 64 data + uint8_t _peer_pubkey_raw[1+64]; + + nRFCrypto_ECC_PrivateKey _private_key; + + uint16_t _ediv; + bond_keys_t* _bond_keys; // Shared keys with bonded device, size ~ 80 bytes + + pair_display_cb_t _display_cb; + pair_complete_cb_t _complete_cb; +}; + +#endif /* BLEPAIRING_H_ */ diff --git a/libraries/Bluefruit52Lib/src/bluefruit.cpp b/libraries/Bluefruit52Lib/src/bluefruit.cpp index c78870d02..fa62e387c 100644 --- a/libraries/Bluefruit52Lib/src/bluefruit.cpp +++ b/libraries/Bluefruit52Lib/src/bluefruit.cpp @@ -37,32 +37,6 @@ #include "bluefruit.h" #include "utility/bonding.h" -#ifdef NRF_CRYPTOCELL -#include "Adafruit_nRFCrypto.h" - -nRFCrypto_ECC _ecpki; -nRFCrypto_ECC_PrivateKey _private_key; -nRFCrypto_ECC_PublicKey _public_key; - -uint8_t _lesc_public_rawkey[1+64]; // 1 byte for header - -// convert 32-byte Number from Big <-> Little Endian to use with BLE -// Public Key = 32-byte N1 + 32-byte N2 -void swap_key_endian(uint8_t rawkey[]) -{ - for(uint8_t i=0; i<32/2; i++) - { - uint8_t const p1 = i; - uint8_t const p2 = (31-i); - - uint8_t temp = rawkey[p1]; - rawkey[p1] = rawkey[p2]; - rawkey[p2] = temp; - } -} - -#endif - #ifndef CFG_BLE_TX_POWER_LEVEL #define CFG_BLE_TX_POWER_LEVEL 0 #endif @@ -203,22 +177,6 @@ AdafruitBluefruit::AdafruitBluefruit(void) _event_cb = NULL; _rssi_cb = NULL; - _pair_display_cb = NULL; - _pair_complete_cb = NULL; - - _sec_param = ((ble_gap_sec_params_t) - { - .bond = 1, - .mitm = 0, - .lesc = 0, - .keypress = 0, - .io_caps = BLE_GAP_IO_CAPS_NONE, - .oob = 0, - .min_key_size = 7, - .max_key_size = 16, - .kdist_own = { .enc = 1, .id = 1}, - .kdist_peer = { .enc = 1, .id = 1}, - }); #ifdef NRF_CRYPTOCELL // _sec_param.lesc = 1; // enable LESC if CryptoCell is present @@ -486,6 +444,8 @@ bool AdafruitBluefruit::begin(uint8_t prph_count, uint8_t central_count) // Init Peripheral role VERIFY( Periph.begin() ); + Pairing.begin(); + // Default device name ble_gap_conn_sec_mode_t sec_mode = BLE_SECMODE_OPEN; VERIFY_STATUS(sd_ble_gap_device_name_set(&sec_mode, (uint8_t const *) CFG_DEFAULT_NAME, strlen(CFG_DEFAULT_NAME)), false); @@ -522,26 +482,6 @@ bool AdafruitBluefruit::begin(uint8_t prph_count, uint8_t central_count) // Initialize bonding bond_init(); - // Initalize Crypto lib for LESC -#ifdef NRF_CRYPTOCELL - nRFCrypto.begin(); - _ecpki.begin(); - - _private_key.begin(CRYS_ECPKI_DomainID_secp256r1); - _public_key.begin(CRYS_ECPKI_DomainID_secp256r1); - - nRFCrypto_ECC::genKeyPair(_private_key, _public_key); - - _public_key.toRaw(_lesc_public_rawkey, sizeof(_lesc_public_rawkey)); -// PRINT_BUFFER(_lesc_public_rawkey+1, sizeof(_lesc_public_rawkey)-1); - - // Public Key = 32-byte N1 + 32-byte N2 - swap_key_endian(_lesc_public_rawkey+1); - swap_key_endian(_lesc_public_rawkey+1+32); - -// PRINT_BUFFER(_lesc_public_rawkey+1, sizeof(_lesc_public_rawkey)-1); -#endif - return true; } @@ -707,69 +647,6 @@ void AdafruitBluefruit::setRssiCallback(rssi_cb_t fp) } -// Use Legacy SC static Passkey -bool AdafruitBluefruit::setPIN(const char* pin) -{ - // back to open mode - if (pin == NULL) - { - _sec_param.bond = 1; - _sec_param.mitm = 0; - _sec_param.lesc = 0; // TODO NRF_CRYPTOCELL - _sec_param.io_caps = BLE_GAP_IO_CAPS_NONE; - }else - { - VERIFY ( strlen(pin) == BLE_GAP_PASSKEY_LEN ); - - // Static Passkey requires using - // - Legacy SC - // - IO cap: Display - // - MITM is on - _sec_param.bond = 1; - _sec_param.mitm = 1; - _sec_param.lesc = 0; - _sec_param.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY; - - ble_opt_t opt; - opt.gap_opt.passkey.p_passkey = (const uint8_t*) pin; - VERIFY_STATUS( sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &opt), false); - } - - return true; -} - -// Pairing using LESC with peripheral display -bool AdafruitBluefruit::setPairingDisplayCallback(pair_display_cb_t fp) -{ - _pair_display_cb = fp; - - if ( fp == NULL ) - { - // TODO callback clear - }else - { - _sec_param.bond = 1; - _sec_param.mitm = 1; - - // TODO NRF_CRYPTOCELL -// _sec_param.lesc = 0; -// _sec_param.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY; - _sec_param.lesc = 1; - _sec_param.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY; - - ble_opt_t opt; - opt.gap_opt.passkey.p_passkey = NULL; // generate Passkey randomly - VERIFY_STATUS( sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &opt), false); - } - - return true; -} - -void AdafruitBluefruit::setPairingCompleteCallback(pair_complete_cb_t fp) -{ - _pair_complete_cb = fp; -} - /*------------------------------------------------------------------*/ /* Thread & SoftDevice Event handler *------------------------------------------------------------------*/ @@ -881,7 +758,11 @@ void AdafruitBluefruit::_ble_handler(ble_evt_t* evt) LOG_LV2("BLE", "%s : Conn Handle = %d", dbg_ble_event_str(evt->header.evt_id), conn_hdl); // GAP handler - if ( conn ) conn->_eventHandler(evt); + if ( conn ) + { + conn->_eventHandler(evt); + Pairing._eventHandler(evt); + } switch(evt->header.evt_id) { @@ -954,30 +835,6 @@ void AdafruitBluefruit::_ble_handler(ble_evt_t* evt) } break; - case BLE_GAP_EVT_PASSKEY_DISPLAY: - { - ble_gap_evt_passkey_display_t const* passkey_display = &evt->evt.gap_evt.params.passkey_display; - LOG_LV2("PAIR", "Passkey = %.6s, match request = %d", passkey_display->passkey, passkey_display->match_request); - - // Invoke display callback - if ( _pair_display_cb ) ada_callback(passkey_display->passkey, 6, _pair_display_cb, conn_hdl, passkey_display->passkey); - - if (passkey_display->match_request) - { - // Match request require to report the match - // sd_ble_gap_auth_key_reply(); - } - } - break; - - case BLE_GAP_EVT_AUTH_STATUS: - { - ble_gap_evt_auth_status_t* status = &evt->evt.gap_evt.params.auth_status; - - if (_pair_complete_cb) ada_callback(NULL, 0, _pair_complete_cb, conn_hdl, status->auth_status); - } - break; - case BLE_EVT_USER_MEM_REQUEST: // We will handle Long Write sequence (RW Authorize PREP_WRITE_REQ) sd_ble_user_mem_reply(conn_hdl, NULL); diff --git a/libraries/Bluefruit52Lib/src/bluefruit.h b/libraries/Bluefruit52Lib/src/bluefruit.h index e3b14db6c..06f8537db 100644 --- a/libraries/Bluefruit52Lib/src/bluefruit.h +++ b/libraries/Bluefruit52Lib/src/bluefruit.h @@ -50,6 +50,7 @@ #include "BLEDiscovery.h" #include "BLEConnection.h" #include "BLEGatt.h" +#include "BLEPairing.h" // Services #include "services/BLEDis.h" @@ -97,21 +98,20 @@ class AdafruitBluefruit public: typedef void (*event_cb_t) (ble_evt_t* evt); typedef void (*rssi_cb_t) (uint16_t conn_hdl, int8_t rssi); - typedef void (*pair_display_cb_t ) (uint16_t conn_hdl, uint8_t const passkey[6]); - typedef void (*pair_complete_cb_t) (uint16_t conn_hdl, uint8_t auth_status); - AdafruitBluefruit(void); // Constructor + AdafruitBluefruit(void); /*------------------------------------------------------------------*/ /* Lower Level Classes (Bluefruit.Advertising.*, etc.) *------------------------------------------------------------------*/ + BLEPeriph Periph; + BLECentral Central; + BLEPairing Pairing; BLEGatt Gatt; BLEAdvertising Advertising; BLEAdvertisingData ScanResponse; BLEScanner Scanner; - BLEPeriph Periph; - BLECentral Central; BLEDiscovery Discovery; /*------------------------------------------------------------------*/ @@ -175,9 +175,6 @@ class AdafruitBluefruit // Security //--------------------------------------------------------------------+ ble_gap_sec_params_t getSecureParam(void) { return _sec_param; } - bool setPIN(const char* pin); // Static Passkey - bool setPairingDisplayCallback(pair_display_cb_t fp); - void setPairingCompleteCallback(pair_complete_cb_t fp); /*------------------------------------------------------------------*/ /* Callbacks @@ -222,6 +219,7 @@ class AdafruitBluefruit SemaphoreHandle_t _ble_event_sem; SemaphoreHandle_t _soc_event_sem; + // Auto LED Blinky TimerHandle_t _led_blink_th; bool _led_conn; @@ -232,8 +230,6 @@ class AdafruitBluefruit //------------- Callbacks -------------// rssi_cb_t _rssi_cb; event_cb_t _event_cb; - pair_display_cb_t _pair_display_cb; - pair_complete_cb_t _pair_complete_cb; /*------------------------------------------------------------------*/ /* INTERNAL USAGE ONLY From 13b66950557c8ae360083d564da71ce718bbf2f2 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 14 Feb 2020 18:19:02 +0700 Subject: [PATCH 15/74] more with BLEPairing --- cores/nRF5/common_func.h | 2 +- .../pairing_display/pairing_display.ino | 2 +- .../Bluefruit52Lib/src/BLEConnection.cpp | 10 ++- libraries/Bluefruit52Lib/src/BLEPairing.cpp | 63 ++++++++++++------- libraries/Bluefruit52Lib/src/BLEPairing.h | 9 +-- libraries/Bluefruit52Lib/src/bluefruit.cpp | 4 -- libraries/Bluefruit52Lib/src/bluefruit.h | 5 -- 7 files changed, 55 insertions(+), 40 deletions(-) diff --git a/cores/nRF5/common_func.h b/cores/nRF5/common_func.h index 27be23eee..2a40da286 100644 --- a/cores/nRF5/common_func.h +++ b/cores/nRF5/common_func.h @@ -157,7 +157,7 @@ const char* dbg_err_str(int32_t err_id); // TODO move to other place #define PRINT_BUFFER(buf, n) \ do {\ uint8_t const* p8 = (uint8_t const*) (buf);\ - PRINTF(#buf ": \n");\ + PRINTF(#buf ": ");\ for(uint32_t i=0; i<(n); i++) {\ if (i%16 == 0) PRINTF("\n"); \ PRINTF("%02x ", p8[i]); \ diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino index cd9279faa..635bdd42f 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino @@ -197,7 +197,7 @@ void loop() void pairing_display_callback(uint16_t conn_handle, uint8_t const passkey[6]) { Serial.println("Enter this code on your phone to pair with Bluefruit:"); - Serial.printf(" %.6s\n", passkey); + Serial.printf(" %.3s %.3s\n", passkey, passkey+3); #if TFT_IN_USE != TFT_NONE tft.printf("Enter this code on your phone to pair with Bluefruit:\n\n"); diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.cpp b/libraries/Bluefruit52Lib/src/BLEConnection.cpp index 738cfd986..4311358ca 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.cpp +++ b/libraries/Bluefruit52Lib/src/BLEConnection.cpp @@ -52,6 +52,9 @@ BLEConnection::BLEConnection(uint16_t conn_hdl, ble_gap_evt_connected_t const* e _peer_addr = evt_connected->peer_addr; _role = evt_connected->role; + _ediv = 0xFFFF; + _bond_keys = NULL; + _hvn_sem = xSemaphoreCreateCounting(hvn_qsize, hvn_qsize); _wrcmd_sem = xSemaphoreCreateCounting(wrcmd_qsize, wrcmd_qsize); @@ -66,7 +69,10 @@ BLEConnection::~BLEConnection() vSemaphoreDelete( _hvn_sem ); vSemaphoreDelete( _wrcmd_sem ); - if ( _hvc_sem ) vSemaphoreDelete( _hvc_sem ); + if (_hvc_sem ) vSemaphoreDelete(_hvc_sem ); + if (_pair_sem ) vSemaphoreDelete(_pair_sem); + + if (_bond_keys ) rtos_free(_bond_keys); } uint16_t BLEConnection::handle (void) @@ -228,7 +234,7 @@ bool BLEConnection::requestPairing(void) // skip if already paired if ( _paired ) return true; - ble_gap_sec_params_t sec_param = Bluefruit.getSecureParam(); + ble_gap_sec_params_t sec_param = Bluefruit.Pairing.getSecureParam(); // on-the-fly semaphore _pair_sem = xSemaphoreCreateBinary(); diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.cpp b/libraries/Bluefruit52Lib/src/BLEPairing.cpp index 762030d18..1503d1307 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.cpp +++ b/libraries/Bluefruit52Lib/src/BLEPairing.cpp @@ -33,16 +33,16 @@ // convert 32-byte Number from Big <-> Little Endian to use with BLE // Public Key = 32-byte N1 + 32-byte N2 -void swap_key_endian(uint8_t rawkey[]) +static void swap_key_endian(uint8_t key[]) { for(uint8_t i=0; i<32/2; i++) { uint8_t const p1 = i; uint8_t const p2 = (31-i); - uint8_t temp = rawkey[p1]; - rawkey[p1] = rawkey[p2]; - rawkey[p2] = temp; + uint8_t temp = key[p1]; + key[p1] = key[p2]; + key[p2] = temp; } } @@ -62,11 +62,17 @@ BLEPairing::BLEPairing(void) .kdist_peer = { .enc = 1, .id = 1}, }); +#ifdef NRF_CRYPTOCELL +// _sec_param.lesc = 1; // enable LESC if CryptoCell is present +#endif + _ediv = EDIV_INVALID; _bond_keys = NULL; _display_cb = NULL; _complete_cb = NULL; + +// _peer_pubkey_raw = NULL; } bool BLEPairing::begin(void) @@ -87,24 +93,18 @@ bool BLEPairing::begin(void) nRFCrypto_ECC::genKeyPair(_private_key, pubkey); // Convert to Raw bytes to response to LESC event - pubkey.toRaw(_public_key_raw, sizeof(_public_key_raw)); + pubkey.toRaw(_pubkey_raw, sizeof(_pubkey_raw)); pubkey.end(); // BLE use Little Endian, swap public key endian // Public Key = 32-byte N1 + 32-byte N2 - swap_key_endian(_public_key_raw+1); - swap_key_endian(_public_key_raw+1+32); + swap_key_endian(_pubkey_raw+1); + swap_key_endian(_pubkey_raw+1+32); #endif return true; } -uint8_t* BLEPairing::getPublicKey(void) -{ - // skip header byte - return _public_key_raw+1; -} - // Use Legacy SC static Passkey bool BLEPairing::setPIN(const char* pin) { @@ -151,7 +151,6 @@ bool BLEPairing::setDisplayCallback(pair_display_cb_t fp) // TODO NRF_CRYPTOCELL // _sec_param.lesc = 0; -// _sec_param.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY; _sec_param.lesc = 1; _sec_param.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY; @@ -200,6 +199,11 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) VERIFY(_bond_keys, ); memclr(_bond_keys, sizeof(bond_keys_t)); + // storing peer public key +// if (_peer_pubkey_raw) rtos_free(_peer_pubkey_raw); +// _peer_pubkey_raw = (uint8_t*) rtos_malloc(1+64); +// VERIFY(_peer_pubkey_raw, ); + _ediv = EDIV_INVALID; /* Step 1: Pairing/Bonding @@ -217,7 +221,7 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) .p_enc_key = &_bond_keys->own_enc, .p_id_key = NULL, .p_sign_key = NULL, - .p_pk = (ble_gap_lesc_p256_pk_t*) (_public_key_raw+1) + .p_pk = (ble_gap_lesc_p256_pk_t*) (_pubkey_raw+1) }, .keys_peer = { @@ -264,22 +268,35 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) // Out of Band not supported yet } - uint8_t peer_raw_pubkey[64+1]; - ble_gap_lesc_dhkey_t dhkey; - - peer_raw_pubkey[0] = CRYS_EC_PointUncompressed; - memcpy(peer_raw_pubkey+1, dhkey_req->p_pk_peer->pk, 64); + // Raw public key from peer device is uncompressed + // _peer_pubkey_raw is dhkey_req->p_pk_peer->pk + _peer_pubkey_raw[0] = CRYS_EC_PointUncompressed; - swap_key_endian(peer_raw_pubkey+1); - swap_key_endian(peer_raw_pubkey+1+32); + // Swap Endian data from air + swap_key_endian(_peer_pubkey_raw+1); + swap_key_endian(_peer_pubkey_raw+1+32); + // Create nRFCrypto pubkey from raw format nRFCrypto_ECC_PublicKey peer_pubkey; peer_pubkey.begin(CRYS_ECPKI_DomainID_secp256r1); - peer_pubkey.fromRaw(peer_raw_pubkey, sizeof(peer_raw_pubkey)); + peer_pubkey.fromRaw(_peer_pubkey_raw, 1+64); + + // Create shared secret derivation primitive using ECC Diffie-Hellman + ble_gap_lesc_dhkey_t dhkey; nRFCrypto_ECC::SVDP_DH(_private_key, peer_pubkey, dhkey.key, sizeof(dhkey.key)); + + //peer_pubkey.end(); +// rtos_free(_peer_pubkey_raw); +// _peer_pubkey_raw = NULL; + + // Swap Endian before sending to air swap_key_endian(dhkey.key); + // Swap back the peer pubkey since SoftDevice still need this until Authentication is complete + swap_key_endian(_peer_pubkey_raw+1); + swap_key_endian(_peer_pubkey_raw+1+32); + sd_ble_gap_lesc_dhkey_reply(conn_hdl, &dhkey); } break; diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.h b/libraries/Bluefruit52Lib/src/BLEPairing.h index 028a52f20..e513b5daa 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.h +++ b/libraries/Bluefruit52Lib/src/BLEPairing.h @@ -41,7 +41,6 @@ class BLEPairing BLEPairing(void); bool begin(void); - uint8_t* getPublicKey(void); // Static Passkey bool setPIN(const char* pin); @@ -55,16 +54,18 @@ class BLEPairing * Although declare as public, it is meant to be invoked by internal * code. User should not call these directly *------------------------------------------------------------------*/ + ble_gap_sec_params_t getSecureParam(void) { return _sec_param; } void _eventHandler(ble_evt_t* evt); private: ble_gap_sec_params_t _sec_param; - uint8_t _public_key_raw[1+64]; // raw key: 1 header + 64 data - uint8_t _peer_pubkey_raw[1+64]; - nRFCrypto_ECC_PrivateKey _private_key; + uint8_t _pubkey_raw[1+64]; // raw key: 1 header + 64 data + + uint8_t _peer_pubkey_raw[1+64]; // filled by SoftDevice + uint16_t _ediv; bond_keys_t* _bond_keys; // Shared keys with bonded device, size ~ 80 bytes diff --git a/libraries/Bluefruit52Lib/src/bluefruit.cpp b/libraries/Bluefruit52Lib/src/bluefruit.cpp index fa62e387c..bf7bbc1c2 100644 --- a/libraries/Bluefruit52Lib/src/bluefruit.cpp +++ b/libraries/Bluefruit52Lib/src/bluefruit.cpp @@ -177,10 +177,6 @@ AdafruitBluefruit::AdafruitBluefruit(void) _event_cb = NULL; _rssi_cb = NULL; - -#ifdef NRF_CRYPTOCELL -// _sec_param.lesc = 1; // enable LESC if CryptoCell is present -#endif } void AdafruitBluefruit::configServiceChanged(bool changed) diff --git a/libraries/Bluefruit52Lib/src/bluefruit.h b/libraries/Bluefruit52Lib/src/bluefruit.h index 06f8537db..3992d5d55 100644 --- a/libraries/Bluefruit52Lib/src/bluefruit.h +++ b/libraries/Bluefruit52Lib/src/bluefruit.h @@ -171,11 +171,6 @@ class AdafruitBluefruit BLEConnection* Connection(uint16_t conn_hdl); - //--------------------------------------------------------------------+ - // Security - //--------------------------------------------------------------------+ - ble_gap_sec_params_t getSecureParam(void) { return _sec_param; } - /*------------------------------------------------------------------*/ /* Callbacks *------------------------------------------------------------------*/ From a739ea12c256fdc12e48f6580b8e891838d5c171 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 14 Feb 2020 18:42:03 +0700 Subject: [PATCH 16/74] add more log to bond/pairing --- libraries/Bluefruit52Lib/src/BLEPairing.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.cpp b/libraries/Bluefruit52Lib/src/BLEPairing.cpp index 1503d1307..81e194e89 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.cpp +++ b/libraries/Bluefruit52Lib/src/BLEPairing.cpp @@ -286,9 +286,7 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) ble_gap_lesc_dhkey_t dhkey; nRFCrypto_ECC::SVDP_DH(_private_key, peer_pubkey, dhkey.key, sizeof(dhkey.key)); - //peer_pubkey.end(); -// rtos_free(_peer_pubkey_raw); -// _peer_pubkey_raw = NULL; + peer_pubkey.end(); // Swap Endian before sending to air swap_key_endian(dhkey.key); @@ -309,10 +307,15 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) LOG_LV2("PAIR", "Auth Status = 0x%02X, Bonded = %d, LESC = %d, Our Kdist = 0x%02X, Peer Kdist = 0x%02X ", status->auth_status, status->bonded, status->lesc, *((uint8_t*) &status->kdist_own), *((uint8_t*) &status->kdist_peer)); +// rtos_free(_peer_pubkey_raw); +// _peer_pubkey_raw = NULL; + // Pairing succeeded --> save encryption keys ( Bonding ) if (BLE_GAP_SEC_STATUS_SUCCESS == status->auth_status) { _ediv = _bond_keys->own_enc.master_id.ediv; + LOG_LV2("PAIR", "Ediv = 0x%02X", _ediv); + bond_save_keys(conn->getRole(), conn_hdl, _bond_keys); // _paired = true; @@ -331,12 +334,16 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) // Peer asks for the stored keys. // - load key and return if bonded previously. // - Else return NULL --> Initiate key exchange - ble_gap_evt_sec_info_request_t* sec_req = (ble_gap_evt_sec_info_request_t*) &evt->evt.gap_evt.params.sec_info_request; + ble_gap_evt_sec_info_request_t* sec_info = (ble_gap_evt_sec_info_request_t*) &evt->evt.gap_evt.params.sec_info_request; + + LOG_LV2("PAIR", "Addr ID = %d, Addr Type = 0x%02X, ediv = 0x%02X", + sec_info->peer_addr.addr_id_peer, sec_info->peer_addr.addr_type, sec_info->master_id.ediv); + LOG_LV2_BUFFER("Address", sec_info->peer_addr.addr, 6); bond_keys_t bkeys; varclr(&bkeys); - if ( bond_load_keys(conn->getRole(), sec_req->master_id.ediv, &bkeys) ) + if ( bond_load_keys(conn->getRole(), sec_info->master_id.ediv, &bkeys) ) { sd_ble_gap_sec_info_reply(conn_hdl, &bkeys.own_enc.enc_info, &bkeys.peer_id.id_info, NULL); From 7991602319baada7abf0433af8b8aaa2cc6d5aa9 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 14 Feb 2020 21:28:56 +0700 Subject: [PATCH 17/74] add resolveAddress with IRK --- libraries/Bluefruit52Lib/src/BLEPairing.cpp | 59 ++++++++++++++++----- libraries/Bluefruit52Lib/src/BLEPairing.h | 3 ++ 2 files changed, 50 insertions(+), 12 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.cpp b/libraries/Bluefruit52Lib/src/BLEPairing.cpp index 81e194e89..c74b0257a 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.cpp +++ b/libraries/Bluefruit52Lib/src/BLEPairing.cpp @@ -33,16 +33,16 @@ // convert 32-byte Number from Big <-> Little Endian to use with BLE // Public Key = 32-byte N1 + 32-byte N2 -static void swap_key_endian(uint8_t key[]) +static void swap_endian(uint8_t data[], uint32_t bytes) { - for(uint8_t i=0; i<32/2; i++) + for(uint8_t i=0; iaddr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE); + + uint8_t const* hash = p_addr->addr; + uint8_t const* rand = p_addr->addr+3; + + nrf_ecb_hal_data_t ecb_data; + memclr(&ecb_data, sizeof(nrf_ecb_hal_data_t)); + + // Swap Endian for IRK (other padding with 0s) + memcpy(ecb_data.key, irk->irk, SOC_ECB_KEY_LENGTH); + swap_endian(ecb_data.key, SOC_ECB_KEY_LENGTH); + + // Swap input endian + memcpy(ecb_data.cleartext, rand, 3); + swap_endian(ecb_data.cleartext, SOC_ECB_CLEARTEXT_LENGTH); + + // compute using HW AES peripherals + (void) sd_ecb_block_encrypt(&ecb_data); + + // Swap output endian + swap_endian(ecb_data.ciphertext, SOC_ECB_CIPHERTEXT_LENGTH); + + return 0 == memcmp(hash, ecb_data.ciphertext, 3); +} + // Use Legacy SC static Passkey bool BLEPairing::setPIN(const char* pin) { @@ -273,8 +306,8 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) _peer_pubkey_raw[0] = CRYS_EC_PointUncompressed; // Swap Endian data from air - swap_key_endian(_peer_pubkey_raw+1); - swap_key_endian(_peer_pubkey_raw+1+32); + swap_endian(_peer_pubkey_raw+1 , 32); + swap_endian(_peer_pubkey_raw+1+32, 32); // Create nRFCrypto pubkey from raw format nRFCrypto_ECC_PublicKey peer_pubkey; @@ -289,11 +322,11 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) peer_pubkey.end(); // Swap Endian before sending to air - swap_key_endian(dhkey.key); + swap_endian(dhkey.key, 32); // Swap back the peer pubkey since SoftDevice still need this until Authentication is complete - swap_key_endian(_peer_pubkey_raw+1); - swap_key_endian(_peer_pubkey_raw+1+32); + swap_endian(_peer_pubkey_raw+1 , 32); + swap_endian(_peer_pubkey_raw+1+32, 32); sd_ble_gap_lesc_dhkey_reply(conn_hdl, &dhkey); } @@ -315,6 +348,7 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) { _ediv = _bond_keys->own_enc.master_id.ediv; LOG_LV2("PAIR", "Ediv = 0x%02X", _ediv); + LOG_LV2_BUFFER("Rand", _bond_keys->own_enc.master_id.rand, 8); bond_save_keys(conn->getRole(), conn_hdl, _bond_keys); @@ -339,6 +373,7 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) LOG_LV2("PAIR", "Addr ID = %d, Addr Type = 0x%02X, ediv = 0x%02X", sec_info->peer_addr.addr_id_peer, sec_info->peer_addr.addr_type, sec_info->master_id.ediv); LOG_LV2_BUFFER("Address", sec_info->peer_addr.addr, 6); + LOG_LV2_BUFFER("Rand", sec_info->master_id.rand, 8); bond_keys_t bkeys; varclr(&bkeys); diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.h b/libraries/Bluefruit52Lib/src/BLEPairing.h index e513b5daa..84270e86b 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.h +++ b/libraries/Bluefruit52Lib/src/BLEPairing.h @@ -45,6 +45,9 @@ class BLEPairing // Static Passkey bool setPIN(const char* pin); + // resolve address with IRK to see if it matches + bool resolveAddress(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * irk); + //------------- Callbacks -------------// bool setDisplayCallback(pair_display_cb_t fp); void setCompleteCallback(pair_complete_cb_t fp); From afdaf93e45780ecfeca1f73070037c8f132c1efa Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 14 Feb 2020 22:05:46 +0700 Subject: [PATCH 18/74] move peer pubkey to member of Connection (better for concurrent support) --- .../Bluefruit52Lib/src/BLEConnection.cpp | 11 ++++-- libraries/Bluefruit52Lib/src/BLEConnection.h | 7 +++- libraries/Bluefruit52Lib/src/BLEPairing.cpp | 39 +++++++++---------- libraries/Bluefruit52Lib/src/BLEPairing.h | 4 +- 4 files changed, 32 insertions(+), 29 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.cpp b/libraries/Bluefruit52Lib/src/BLEConnection.cpp index 4311358ca..848e38658 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.cpp +++ b/libraries/Bluefruit52Lib/src/BLEConnection.cpp @@ -52,9 +52,6 @@ BLEConnection::BLEConnection(uint16_t conn_hdl, ble_gap_evt_connected_t const* e _peer_addr = evt_connected->peer_addr; _role = evt_connected->role; - _ediv = 0xFFFF; - _bond_keys = NULL; - _hvn_sem = xSemaphoreCreateCounting(hvn_qsize, hvn_qsize); _wrcmd_sem = xSemaphoreCreateCounting(wrcmd_qsize, wrcmd_qsize); @@ -62,6 +59,10 @@ BLEConnection::BLEConnection(uint16_t conn_hdl, ble_gap_evt_connected_t const* e _hvc_sem = NULL; _hvc_received = false; _pair_sem = NULL; + + _ediv = 0xFFFF; + _bond_keys = NULL; + _peer_pubkey = NULL; } BLEConnection::~BLEConnection() @@ -69,10 +70,12 @@ BLEConnection::~BLEConnection() vSemaphoreDelete( _hvn_sem ); vSemaphoreDelete( _wrcmd_sem ); + //------------- on-the-fly data must be freed -------------// if (_hvc_sem ) vSemaphoreDelete(_hvc_sem ); if (_pair_sem ) vSemaphoreDelete(_pair_sem); - if (_bond_keys ) rtos_free(_bond_keys); + if (_bond_keys ) rtos_free(_bond_keys); + if (_peer_pubkey ) rtos_free(_peer_pubkey); } uint16_t BLEConnection::handle (void) diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.h b/libraries/Bluefruit52Lib/src/BLEConnection.h index 4be26b834..b22180caa 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.h +++ b/libraries/Bluefruit52Lib/src/BLEConnection.h @@ -64,9 +64,10 @@ class BLEConnection // On-demand semaphore/data that are created on the fly SemaphoreHandle_t _hvc_sem; - SemaphoreHandle_t _pair_sem; - bond_keys_t* _bond_keys; // Shared keys with bonded device, size ~ 80 bytes + + bond_keys_t* _bond_keys; // Shared keys with bonded device, size ~ 80 bytes + uint8_t* _peer_pubkey; // LESC Peer public key public: BLEConnection(uint16_t conn_hdl, ble_gap_evt_connected_t const * evt_connected, uint8_t hvn_qsize, uint8_t wrcmd_qsize); @@ -111,6 +112,8 @@ class BLEConnection * Although declare as public, it is meant to be invoked by internal code. *------------------------------------------------------------------*/ void _eventHandler(ble_evt_t* evt); + + friend class BLEPairing; }; diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.cpp b/libraries/Bluefruit52Lib/src/BLEPairing.cpp index c74b0257a..0ae1e9219 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.cpp +++ b/libraries/Bluefruit52Lib/src/BLEPairing.cpp @@ -71,8 +71,6 @@ BLEPairing::BLEPairing(void) _display_cb = NULL; _complete_cb = NULL; - -// _peer_pubkey_raw = NULL; } bool BLEPairing::begin(void) @@ -232,10 +230,10 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) VERIFY(_bond_keys, ); memclr(_bond_keys, sizeof(bond_keys_t)); - // storing peer public key -// if (_peer_pubkey_raw) rtos_free(_peer_pubkey_raw); -// _peer_pubkey_raw = (uint8_t*) rtos_malloc(1+64); -// VERIFY(_peer_pubkey_raw, ); + // storing peer public key in connection + if (conn->_peer_pubkey) rtos_free(conn->_peer_pubkey); + conn->_peer_pubkey = (uint8_t*) rtos_malloc(1+BLE_GAP_LESC_P256_PK_LEN); + VERIFY(conn->_peer_pubkey, ); _ediv = EDIV_INVALID; @@ -261,7 +259,7 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) .p_enc_key = &_bond_keys->peer_enc, .p_id_key = &_bond_keys->peer_id, .p_sign_key = NULL, - .p_pk = (ble_gap_lesc_p256_pk_t*) (_peer_pubkey_raw+1) + .p_pk = (ble_gap_lesc_p256_pk_t*) (conn->_peer_pubkey+1) } }; @@ -302,31 +300,32 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) } // Raw public key from peer device is uncompressed - // _peer_pubkey_raw is dhkey_req->p_pk_peer->pk - _peer_pubkey_raw[0] = CRYS_EC_PointUncompressed; + // _peer_pubkey + 1 == dhkey_req->p_pk_peer->pk + uint8_t* peer_pubkey = conn->_peer_pubkey; + peer_pubkey[0] = CRYS_EC_PointUncompressed; // Swap Endian data from air - swap_endian(_peer_pubkey_raw+1 , 32); - swap_endian(_peer_pubkey_raw+1+32, 32); + swap_endian(peer_pubkey+1 , 32); + swap_endian(peer_pubkey+1+32, 32); // Create nRFCrypto pubkey from raw format - nRFCrypto_ECC_PublicKey peer_pubkey; - peer_pubkey.begin(CRYS_ECPKI_DomainID_secp256r1); + nRFCrypto_ECC_PublicKey peerPublickKey; + peerPublickKey.begin(CRYS_ECPKI_DomainID_secp256r1); - peer_pubkey.fromRaw(_peer_pubkey_raw, 1+64); + peerPublickKey.fromRaw(peer_pubkey, 1+BLE_GAP_LESC_P256_PK_LEN); // Create shared secret derivation primitive using ECC Diffie-Hellman ble_gap_lesc_dhkey_t dhkey; - nRFCrypto_ECC::SVDP_DH(_private_key, peer_pubkey, dhkey.key, sizeof(dhkey.key)); + nRFCrypto_ECC::SVDP_DH(_private_key, peerPublickKey, dhkey.key, sizeof(dhkey.key)); - peer_pubkey.end(); + peerPublickKey.end(); // Swap Endian before sending to air swap_endian(dhkey.key, 32); // Swap back the peer pubkey since SoftDevice still need this until Authentication is complete - swap_endian(_peer_pubkey_raw+1 , 32); - swap_endian(_peer_pubkey_raw+1+32, 32); + swap_endian(peer_pubkey+1 , 32); + swap_endian(peer_pubkey+1+32, 32); sd_ble_gap_lesc_dhkey_reply(conn_hdl, &dhkey); } @@ -340,8 +339,8 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) LOG_LV2("PAIR", "Auth Status = 0x%02X, Bonded = %d, LESC = %d, Our Kdist = 0x%02X, Peer Kdist = 0x%02X ", status->auth_status, status->bonded, status->lesc, *((uint8_t*) &status->kdist_own), *((uint8_t*) &status->kdist_peer)); -// rtos_free(_peer_pubkey_raw); -// _peer_pubkey_raw = NULL; + rtos_free(conn->_peer_pubkey); + conn->_peer_pubkey = NULL; // Pairing succeeded --> save encryption keys ( Bonding ) if (BLE_GAP_SEC_STATUS_SUCCESS == status->auth_status) diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.h b/libraries/Bluefruit52Lib/src/BLEPairing.h index 84270e86b..9c716cb92 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.h +++ b/libraries/Bluefruit52Lib/src/BLEPairing.h @@ -65,9 +65,7 @@ class BLEPairing nRFCrypto_ECC_PrivateKey _private_key; - uint8_t _pubkey_raw[1+64]; // raw key: 1 header + 64 data - - uint8_t _peer_pubkey_raw[1+64]; // filled by SoftDevice + uint8_t _pubkey_raw[1+BLE_GAP_LESC_P256_PK_LEN]; // raw key: 1 header + 64 data uint16_t _ediv; bond_keys_t* _bond_keys; // Shared keys with bonded device, size ~ 80 bytes From 95fd6aaf36f866cea00e741f6076339c65ed9d25 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 17 Feb 2020 10:11:43 +0700 Subject: [PATCH 19/74] bond debug --- libraries/Bluefruit52Lib/src/utility/bonding.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/Bluefruit52Lib/src/utility/bonding.cpp b/libraries/Bluefruit52Lib/src/utility/bonding.cpp index a01b33638..28f53e33e 100644 --- a/libraries/Bluefruit52Lib/src/utility/bonding.cpp +++ b/libraries/Bluefruit52Lib/src/utility/bonding.cpp @@ -43,7 +43,7 @@ using namespace Adafruit_LittleFS_Namespace; -#define BOND_DEBUG 0 +#define BOND_DEBUG 1 #if (CFG_DEBUG == 1 && BOND_DEBUG == 1) || (CFG_DEBUG >= 2) #define BOND_LOG(...) LOG_LV1("BOND", __VA_ARGS__) From aadf097cf76acbb2fb8df1bd596e1cc80e116f49 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 17 Feb 2020 16:09:59 +0700 Subject: [PATCH 20/74] clean up --- libraries/Bluefruit52Lib/src/BLEPairing.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.cpp b/libraries/Bluefruit52Lib/src/BLEPairing.cpp index 0ae1e9219..108de5df5 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.cpp +++ b/libraries/Bluefruit52Lib/src/BLEPairing.cpp @@ -128,12 +128,13 @@ bool BLEPairing::resolveAddress(ble_gap_addr_t const * p_addr, ble_gap_irk_t con swap_endian(ecb_data.cleartext, SOC_ECB_CLEARTEXT_LENGTH); // compute using HW AES peripherals - (void) sd_ecb_block_encrypt(&ecb_data); + // TODO use CC310 to compute AES + (void) sd_ecb_block_encrypt(&ecb_data); - // Swap output endian - swap_endian(ecb_data.ciphertext, SOC_ECB_CIPHERTEXT_LENGTH); + // Swap output endian + swap_endian(ecb_data.ciphertext, SOC_ECB_CIPHERTEXT_LENGTH); - return 0 == memcmp(hash, ecb_data.ciphertext, 3); + return 0 == memcmp(hash, ecb_data.ciphertext, 3); } // Use Legacy SC static Passkey From f0f722effc08223d97a81e90677933993609c3bf Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 19 Feb 2020 23:11:46 +0700 Subject: [PATCH 21/74] ci install nRFCrypto --- .github/workflows/githubci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/githubci.yml b/.github/workflows/githubci.yml index 4816c2be4..230eff8b9 100644 --- a/.github/workflows/githubci.yml +++ b/.github/workflows/githubci.yml @@ -53,7 +53,7 @@ jobs: ln -s $GITHUB_WORKSPACE $HOME/$BSP_PATH/$BSP_VERSION # Install library dependency arduino-cli lib install "Adafruit GFX Library" "Adafruit SSD1306" "Adafruit ILI9341" "Adafruit HX8357 Library" "Adafruit EPD" - arduino-cli lib install "Adafruit Circuit Playground" "Adafruit NeoPixel" "Adafruit NeoMatrix" "MIDI Library" "Firmata" + arduino-cli lib install "Adafruit nRFCrypto" "Adafruit Circuit Playground" "Adafruit NeoPixel" "Adafruit NeoMatrix" "MIDI Library" "Firmata" - name: Build examples run: python3 tools/build_all.py ${{ matrix.arduino-platform }} From 565cf6d98610dc6c1328d9de43bf761d3ba05e2e Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 13 Mar 2020 13:05:40 +0700 Subject: [PATCH 22/74] fix ci using arduino-cli 0.8.0 to be able to compile nRFCrypto --- .github/workflows/githubci.yml | 7 ++++++- tools/build_all.py | 5 ++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/githubci.yml b/.github/workflows/githubci.yml index 6ff9d7b88..edef72962 100644 --- a/.github/workflows/githubci.yml +++ b/.github/workflows/githubci.yml @@ -35,7 +35,12 @@ jobs: mkdir $HOME/.arduino15/packages mkdir $HOME/Arduino mkdir $HOME/Arduino/libraries - curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh + # FIXME use arduino-cli 0.8.0 due to 0.9.0/IDE 1.8.2 precompiled hanlding broke nRFCypto + # https://github.com/arduino/arduino-builder/issues/353 + #curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh + wget https://github.com/arduino/arduino-cli/releases/download/0.8.0/arduino-cli_0.8.0_Linux_64bit.tar.gzw + mkdir bin + tar -xf arduino-cli_0.8.0_Linux_64bit.tar.gz -C bin echo "::add-path::$GITHUB_WORKSPACE/bin" - name: Install BSP and Libraries diff --git a/tools/build_all.py b/tools/build_all.py index 62f467572..1acdbe4df 100644 --- a/tools/build_all.py +++ b/tools/build_all.py @@ -44,7 +44,10 @@ def build_examples(variant): fqbn = "adafruit:nrf52:{}:softdevice={},debug=l0".format(variant, 's140v6' if variant != 'feather52832' else 's132v6') - for sketch in glob.iglob('libraries/**/*.ino', recursive=True): + all_sketches = list(glob.iglob('libraries/**/*.ino', recursive=True)) + all_sketches.sort() + + for sketch in all_sketches: start_time = time.monotonic() # Skip if contains: ".board.test.skip" or ".all.test.skip" From 59e92ec28f299c5cf21f02f1ceef86b08c73f769 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 13 Mar 2020 13:18:38 +0700 Subject: [PATCH 23/74] temporary use arduino-cli 0.7.2 instead of latest (0.9.0) for building --- .github/workflows/githubci.yml | 4 ++-- tools/build_all.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/githubci.yml b/.github/workflows/githubci.yml index edef72962..b86c5643f 100644 --- a/.github/workflows/githubci.yml +++ b/.github/workflows/githubci.yml @@ -35,10 +35,10 @@ jobs: mkdir $HOME/.arduino15/packages mkdir $HOME/Arduino mkdir $HOME/Arduino/libraries - # FIXME use arduino-cli 0.8.0 due to 0.9.0/IDE 1.8.2 precompiled hanlding broke nRFCypto + # FIXME use arduino-cli 0.7.2 due to 0.9.0/IDE 1.8.2 precompiled hanlding broke nRFCypto # https://github.com/arduino/arduino-builder/issues/353 #curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh - wget https://github.com/arduino/arduino-cli/releases/download/0.8.0/arduino-cli_0.8.0_Linux_64bit.tar.gzw + wget https://github.com/arduino/arduino-cli/releases/download/0.7.2/arduino-cli_0.7.2_Linux_64bit.tar.gz mkdir bin tar -xf arduino-cli_0.8.0_Linux_64bit.tar.gz -C bin echo "::add-path::$GITHUB_WORKSPACE/bin" diff --git a/tools/build_all.py b/tools/build_all.py index 1acdbe4df..37327ba33 100644 --- a/tools/build_all.py +++ b/tools/build_all.py @@ -10,7 +10,7 @@ fail_count = 0 skip_count = 0 -build_format = '| {:20} | {:35} | {:9} ' +build_format = '| {:20} | {:35} | {:9} | {:6} |' build_separator = '-' * 83 default_boards = [ 'cluenrf52840', 'cplaynrf52840', 'feather52832', 'feather52840', 'feather52840sense', 'itsybitsy52840' ] @@ -39,7 +39,7 @@ def build_examples(variant): print(build_separator) print('| {:^79} |'.format('Board ' + variant)) print(build_separator) - print((build_format + '| {:6} |').format('Library', 'Example', 'Result', 'Time')) + print((build_format).format('Library', 'Example', 'Result', 'Time')) print(build_separator) fqbn = "adafruit:nrf52:{}:softdevice={},debug=l0".format(variant, 's140v6' if variant != 'feather52832' else 's132v6') @@ -86,7 +86,7 @@ def build_examples(variant): build_duration = time.monotonic() - start_time - print((build_format + '| {:5.2f}s |').format(sketch.split(os.path.sep)[1], os.path.basename(sketch), success, build_duration)) + print((build_format).format(sketch.split(os.path.sep)[1], os.path.basename(sketch), success, "{:.2f}".format(build_duration))) if success != "\033[33mskipped\033[0m ": if build_result.returncode != 0: From 9104585fe09b3aba0a1bc1fa2c34d5d68cef9774 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 13 Mar 2020 13:23:49 +0700 Subject: [PATCH 24/74] fix ci --- .github/workflows/githubci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/githubci.yml b/.github/workflows/githubci.yml index b86c5643f..e04798053 100644 --- a/.github/workflows/githubci.yml +++ b/.github/workflows/githubci.yml @@ -40,7 +40,7 @@ jobs: #curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh wget https://github.com/arduino/arduino-cli/releases/download/0.7.2/arduino-cli_0.7.2_Linux_64bit.tar.gz mkdir bin - tar -xf arduino-cli_0.8.0_Linux_64bit.tar.gz -C bin + tar -xf arduino-cli_0.7.2_Linux_64bit.tar.gz -C bin echo "::add-path::$GITHUB_WORKSPACE/bin" - name: Install BSP and Libraries From 8f554493db52b251c946667d3b10429dd7449f66 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 13 Mar 2020 16:17:24 +0700 Subject: [PATCH 25/74] fix swap endian, tested resolveAddress() --- libraries/Bluefruit52Lib/src/BLEPairing.cpp | 26 +++++++++++++++------ 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.cpp b/libraries/Bluefruit52Lib/src/BLEPairing.cpp index 108de5df5..bf7a5a6c1 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.cpp +++ b/libraries/Bluefruit52Lib/src/BLEPairing.cpp @@ -31,14 +31,14 @@ //------------- IMPLEMENTATION -------------// -// convert 32-byte Number from Big <-> Little Endian to use with BLE +// convert N-byte Number from Big <-> Little Endian to use with BLE // Public Key = 32-byte N1 + 32-byte N2 -static void swap_endian(uint8_t data[], uint32_t bytes) +static void swap_endian(uint8_t data[], uint32_t nbytes) { - for(uint8_t i=0; i_peer_pubkey) rtos_free(conn->_peer_pubkey); - conn->_peer_pubkey = (uint8_t*) rtos_malloc(1+BLE_GAP_LESC_P256_PK_LEN); + if (!conn->_peer_pubkey) + { + conn->_peer_pubkey = (uint8_t*) rtos_malloc(1+BLE_GAP_LESC_P256_PK_LEN); + } VERIFY(conn->_peer_pubkey, ); _ediv = EDIV_INVALID; @@ -312,7 +314,6 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) // Create nRFCrypto pubkey from raw format nRFCrypto_ECC_PublicKey peerPublickKey; peerPublickKey.begin(CRYS_ECPKI_DomainID_secp256r1); - peerPublickKey.fromRaw(peer_pubkey, 1+BLE_GAP_LESC_P256_PK_LEN); // Create shared secret derivation primitive using ECC Diffie-Hellman @@ -350,6 +351,10 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) LOG_LV2("PAIR", "Ediv = 0x%02X", _ediv); LOG_LV2_BUFFER("Rand", _bond_keys->own_enc.master_id.rand, 8); + //PRINT_INT(_bond_keys->peer_id.id_addr_info.addr_type); + //Serial.printBufferReverse(_bond_keys->peer_id.id_addr_info.addr, 6, ':'); + //Serial.println(); + bond_save_keys(conn->getRole(), conn_hdl, _bond_keys); // _paired = true; @@ -378,8 +383,15 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) bond_keys_t bkeys; varclr(&bkeys); + // TODO Random Static + + // Resolvable + + if ( bond_load_keys(conn->getRole(), sec_info->master_id.ediv, &bkeys) ) { +// PRINT_INT(resolveAddress(&sec_info->peer_addr, &bkeys.peer_id.id_info)); + sd_ble_gap_sec_info_reply(conn_hdl, &bkeys.own_enc.enc_info, &bkeys.peer_id.id_info, NULL); _ediv = bkeys.own_enc.master_id.ediv; From cd45f0adc2c412dce2fc5204b6b5f686070ca2a9 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 14 Mar 2020 11:47:27 +0700 Subject: [PATCH 26/74] move clearBonds() to PrPh --- .../Peripheral/clearbonds/clearbonds.ino | 4 +- libraries/Bluefruit52Lib/src/BLECentral.h | 2 +- libraries/Bluefruit52Lib/src/BLEPeriph.cpp | 5 ++ libraries/Bluefruit52Lib/src/BLEPeriph.h | 2 + libraries/Bluefruit52Lib/src/bluefruit.cpp | 5 -- libraries/Bluefruit52Lib/src/bluefruit.h | 2 - .../Bluefruit52Lib/src/utility/bonding.cpp | 74 +++++++++++++++---- .../Bluefruit52Lib/src/utility/bonding.h | 4 +- 8 files changed, 70 insertions(+), 28 deletions(-) diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/clearbonds/clearbonds.ino b/libraries/Bluefruit52Lib/examples/Peripheral/clearbonds/clearbonds.ino index d6770d449..7e0c59b2b 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/clearbonds/clearbonds.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/clearbonds/clearbonds.ino @@ -22,7 +22,7 @@ void setup() { Serial.begin(115200); - while ( !Serial ) delay(10); // for nrf52840 with native usb +// while ( !Serial ) delay(10); // for nrf52840 with native usb Serial.println("Bluefruit52 Clear Bonds Example"); Serial.println("-------------------------------\n"); @@ -34,7 +34,7 @@ void setup() bond_print_list(BLE_GAP_ROLE_PERIPH); bond_print_list(BLE_GAP_ROLE_CENTRAL); - Bluefruit.clearBonds(); + Bluefruit.Periph.clearBonds(); Bluefruit.Central.clearBonds(); Serial.println(); diff --git a/libraries/Bluefruit52Lib/src/BLECentral.h b/libraries/Bluefruit52Lib/src/BLECentral.h index 8372a2201..c5b5bd379 100644 --- a/libraries/Bluefruit52Lib/src/BLECentral.h +++ b/libraries/Bluefruit52Lib/src/BLECentral.h @@ -59,7 +59,7 @@ class BLECentral bool connected(uint16_t conn_hdl); // Connected as central to this connection uint8_t connected(void); // Number of connected as central - void clearBonds (void); + void clearBonds(void); /*------------- Callbacks -------------*/ void setConnectCallback ( ble_connect_callback_t fp); diff --git a/libraries/Bluefruit52Lib/src/BLEPeriph.cpp b/libraries/Bluefruit52Lib/src/BLEPeriph.cpp index 303cf478e..fab8908db 100644 --- a/libraries/Bluefruit52Lib/src/BLEPeriph.cpp +++ b/libraries/Bluefruit52Lib/src/BLEPeriph.cpp @@ -78,6 +78,11 @@ uint8_t BLEPeriph::connected (void) return count; } +void BLEPeriph::clearBonds(void) +{ + bond_clear_prph(); +} + bool BLEPeriph::setConnInterval (uint16_t min, uint16_t max) { _ppcp.min_conn_interval = min; diff --git a/libraries/Bluefruit52Lib/src/BLEPeriph.h b/libraries/Bluefruit52Lib/src/BLEPeriph.h index 12491533d..2649e928b 100644 --- a/libraries/Bluefruit52Lib/src/BLEPeriph.h +++ b/libraries/Bluefruit52Lib/src/BLEPeriph.h @@ -50,6 +50,8 @@ class BLEPeriph bool connected(uint16_t conn_hdl); // Connected as prph to this connection uint8_t connected(void); // Number of connected as peripherals + void clearBonds(void); + bool setConnInterval (uint16_t min, uint16_t max); bool setConnIntervalMS (uint16_t min_ms, uint16_t max_ms); bool setConnSupervisionTimeout(uint16_t timeout); diff --git a/libraries/Bluefruit52Lib/src/bluefruit.cpp b/libraries/Bluefruit52Lib/src/bluefruit.cpp index ed02a5b8b..9fe0b6f6b 100644 --- a/libraries/Bluefruit52Lib/src/bluefruit.cpp +++ b/libraries/Bluefruit52Lib/src/bluefruit.cpp @@ -927,11 +927,6 @@ bool AdafruitBluefruit::requestPairing(uint16_t conn_hdl) return conn->requestPairing(); } -void AdafruitBluefruit::clearBonds(void) -{ - bond_clear_prph(); -} - //--------------------------------------------------------------------+ // //--------------------------------------------------------------------+ diff --git a/libraries/Bluefruit52Lib/src/bluefruit.h b/libraries/Bluefruit52Lib/src/bluefruit.h index f0efab19a..c58f6bcba 100644 --- a/libraries/Bluefruit52Lib/src/bluefruit.h +++ b/libraries/Bluefruit52Lib/src/bluefruit.h @@ -157,8 +157,6 @@ class AdafruitBluefruit void autoConnLed (bool enabled); void setConnLedInterval (uint32_t ms); - void clearBonds (void); - /*------------------------------------------------------------------*/ /* GAP, Connections and Bonding *------------------------------------------------------------------*/ diff --git a/libraries/Bluefruit52Lib/src/utility/bonding.cpp b/libraries/Bluefruit52Lib/src/utility/bonding.cpp index 28f53e33e..5d402ff08 100644 --- a/libraries/Bluefruit52Lib/src/utility/bonding.cpp +++ b/libraries/Bluefruit52Lib/src/utility/bonding.cpp @@ -60,7 +60,7 @@ using namespace Adafruit_LittleFS_Namespace; * Each field has an 1-byte preceding length *------------------------------------------------------------------*/ #define SVC_CONTEXT_FLAG (BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS | BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS) -#define BOND_FNAME_LEN max(sizeof(BOND_FNAME_PRPH), sizeof(BOND_FNAME_CNTR)) +#define BOND_FNAME_LEN (max(sizeof(BOND_FNAME_PRPH), sizeof(BOND_FNAME_CNTR)) + 8)// TODO refactor later static void get_fname (char* fname, uint8_t role, uint16_t ediv) { @@ -94,12 +94,18 @@ void bond_init(void) /*------------------------------------------------------------------*/ /* Keys *------------------------------------------------------------------*/ -static void bond_save_keys_dfr (uint8_t role, uint16_t conn_hdl, bond_keys_t* bkeys) +static void bond_save_keys_dfr (uint8_t role, uint16_t conn_hdl, bool lesc, bond_keys_t* bkeys) { uint16_t const ediv = (role == BLE_GAP_ROLE_PERIPH) ? bkeys->own_enc.master_id.ediv : bkeys->peer_enc.master_id.ediv; + // Bond store keys using peer mac address e.g 1a2b3c4d5e6f + char filename[BOND_FNAME_LEN]; - get_fname(filename, role, ediv); +// get_fname(filename, role, ediv); + + uint8_t const * mac = bkeys->peer_id.id_addr_info.addr; + sprintf(filename, BOND_DIR_PRPH "/%02X%02X%02X%02X%02X%02X", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); // delete if file already exists if ( InternalFS.exists(filename) ) InternalFS.remove(filename); @@ -117,7 +123,6 @@ static void bond_save_keys_dfr (uint8_t role, uint16_t conn_hdl, bond_keys_t* bk // If couldn't get devname then use peer mac address if ( !devname[0] ) { - uint8_t* mac = bkeys->peer_id.id_addr_info.addr; sprintf(devname, "%02X:%02X:%02X:%02X:%02X:%02X", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]); } @@ -128,29 +133,66 @@ static void bond_save_keys_dfr (uint8_t role, uint16_t conn_hdl, bond_keys_t* bk file.close(); } -bool bond_save_keys (uint8_t role, uint16_t conn_hdl, bond_keys_t* bkeys) +bool bond_save_keys (uint8_t role, uint16_t conn_hdl, bond_keys_t const* bkeys) { // queue to execute in Ada Callback thread return ada_callback(bkeys, sizeof(bond_keys_t), bond_save_keys_dfr, role, conn_hdl, bkeys); } -bool bond_load_keys(uint8_t role, uint16_t ediv, bond_keys_t* bkeys) +bool bond_load_keys(uint8_t role, ble_gap_addr_t* addr, bond_keys_t* bkeys) { - char filename[BOND_FNAME_LEN]; - get_fname(filename, role, ediv); + bool ret = false; - File file(filename, FILE_O_READ, InternalFS); - VERIFY(file); + switch(addr->addr_type) + { + case BLE_GAP_ADDR_TYPE_PUBLIC: + case BLE_GAP_ADDR_TYPE_RANDOM_STATIC: + { + // Peer probably uses RANDOM_STATIC or in rarer case PUBLIC + // Address is used as identity - int keylen = file.read(); - VERIFY(keylen == sizeof(bond_keys_t)); + char filename[BOND_FNAME_LEN]; + // get_fname(filename, role, ediv); + sprintf(filename, BOND_DIR_PRPH "/%02X%02X%02X%02X%02X%02X", + addr->addr[0], addr->addr[1], addr->addr[2], addr->addr[3], addr->addr[4], addr->addr[5]); - file.read(bkeys, keylen); - file.close(); + File file(InternalFS); + VERIFY( file.open(filename, FILE_O_READ) ); + BOND_LOG("Loaded keys from file %s", filename); + } + break; - BOND_LOG("Loaded keys from file %s", filename); + case BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE: + { + // Resolvable address, we have to go through the whole list to perform IRK Address matching + char const * dpath = (role == BLE_GAP_ROLE_PERIPH ? BOND_DIR_PRPH : BOND_DIR_CNTR); + File dir(dpath, FILE_O_READ, InternalFS); + File file(InternalFS); - return true; + while ( !ret && (file = dir.openNextFile(FILE_O_READ)) ) + { + int keylen = file.read(); + if ( keylen == sizeof(bond_keys_t) ) + { + file.read((uint8_t*) bkeys, keylen); + if ( Bluefruit.Pairing.resolveAddress(addr, &bkeys->peer_id.id_info) ) + { + BOND_LOG("Loaded keys from file %s/%s", dpath, file.name()); + ret = true; + } + } + + file.close(); + } + + dir.close(); + } + break; + + default: return false; // Non Resolvable & Anonymous are not supported + } + + return ret; } diff --git a/libraries/Bluefruit52Lib/src/utility/bonding.h b/libraries/Bluefruit52Lib/src/utility/bonding.h index b23cb2c5d..396b9797f 100644 --- a/libraries/Bluefruit52Lib/src/utility/bonding.h +++ b/libraries/Bluefruit52Lib/src/utility/bonding.h @@ -59,8 +59,8 @@ void bond_clear_all(void); void bond_remove_key(uint8_t role, uint16_t ediv); -bool bond_save_keys (uint8_t role, uint16_t conn_hdl, bond_keys_t* bkeys); -bool bond_load_keys(uint8_t role, uint16_t ediv, bond_keys_t* bkeys); +bool bond_save_keys (uint8_t role, uint16_t conn_hdl, bond_keys_t const* bkeys); +bool bond_load_keys(uint8_t role, ble_gap_addr_t*, bond_keys_t* bkeys); bool bond_save_cccd (uint8_t role, uint16_t conn_hdl, uint16_t ediv); bool bond_load_cccd (uint8_t role, uint16_t conn_hdl, uint16_t ediv); From b5ca5d03873459423575a7b5902dba8329bffcbe Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 14 Mar 2020 13:40:40 +0700 Subject: [PATCH 27/74] reworking bonding, save/load using ID Address instead of ediv --- .../Bluefruit52Lib/src/BLEConnection.cpp | 57 +++++------ libraries/Bluefruit52Lib/src/BLEConnection.h | 11 ++- libraries/Bluefruit52Lib/src/BLEGatt.cpp | 2 +- libraries/Bluefruit52Lib/src/BLEPairing.cpp | 25 +---- .../Bluefruit52Lib/src/utility/bonding.cpp | 97 +++++++++---------- .../Bluefruit52Lib/src/utility/bonding.h | 10 +- 6 files changed, 90 insertions(+), 112 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.cpp b/libraries/Bluefruit52Lib/src/BLEConnection.cpp index 3c9878803..9d8f7bbb8 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.cpp +++ b/libraries/Bluefruit52Lib/src/BLEConnection.cpp @@ -227,14 +227,36 @@ bool BLEConnection::getWriteCmdPacket (void) return xSemaphoreTake(_wrcmd_sem, ms2tick(BLE_GENERIC_TIMEOUT)); } -bool BLEConnection::storeCccd(void) +bool BLEConnection::saveCccd(void) { - return bond_save_cccd( _role, _conn_hdl, _ediv); + return bond_save_cccd(_role, _conn_hdl, &_bond_id_addr); +} + +bool BLEConnection::loadCccd(void) +{ + return bond_load_cccd(_role, _conn_hdl, &_bond_id_addr); +} + +bool BLEConnection::_saveLongTermKey(bond_keys_t const* ltkey) +{ + bond_save_keys(_role, _conn_hdl, ltkey); + _bond_id_addr = ltkey->peer_id.id_addr_info; + _paired = true; // paired with new device + return true; +} + +bool BLEConnection::_loadLongTermKey(bond_keys_t* ltkey) +{ + VERIFY( bond_load_keys(_role, &_peer_addr, ltkey) ); + _bond_id_addr = ltkey->peer_id.id_addr_info; + return true; } bool BLEConnection::loadKeys(bond_keys_t* bkeys) { - return bond_load_keys(_role, _ediv, bkeys); + return false; + // FIXME dfu key sharing later + //return bond_load_keys(_role, _ediv, bkeys); } bool BLEConnection::requestPairing(void) @@ -276,6 +298,7 @@ bool BLEConnection::requestPairing(void) // Prph delete bonds while we did not --> let's remove the obsolete keyfile and retry if ( !_paired && (cntr_ediv != 0xffff) ) { + // FIXME central remove key bond_remove_key(BLE_GAP_ROLE_CENTRAL, cntr_ediv); // Re-try with a fresh session @@ -314,34 +337,6 @@ void BLEConnection::_eventHandler(ble_evt_t* evt) _connected = false; break; - //--------------------------------------------------------------------+ - /* First-time Pairing - * - * Connect -> SEC_PARAMS_REQUEST -> PASSKEY_DISPLAY -> BLE_GAP_EVT_LESC_DHKEY_REQUEST -> - * CONN_SEC_UPDATE -> AUTH_STATUS - * 1. Either we or peer initiate the process - * 2. Peer ask for Secure Parameter ( I/O Caps ) BLE_GAP_EVT_SEC_PARAMS_REQUEST - * 3. Pair PassKey exchange - * 4. Connection is secured BLE_GAP_EVT_CONN_SEC_UPDATE - * 5. Long term Keys exchanged BLE_GAP_EVT_AUTH_STATUS - * - * Reconnect using bonded key - * Connect -> SEC_INFO_REQUEST -> CONN_SEC_UPDATE - * 1. Either we or peer initiate the process - * 2. Peer ask for Secure Info ( bond keys ) BLE_GAP_EVT_SEC_INFO_REQUEST - * 3. Connection is secured BLE_GAP_EVT_CONN_SEC_UPDATE - */ - //--------------------------------------------------------------------+ - - case BLE_GAP_EVT_AUTH_STATUS: - { - ble_gap_evt_auth_status_t* status = &evt->evt.gap_evt.params.auth_status; - - // Pairing succeeded - if (BLE_GAP_SEC_STATUS_SUCCESS == status->auth_status) _paired = true; - } - break; - case BLE_GAP_EVT_CONN_SEC_UPDATE: { const ble_gap_conn_sec_t* conn_sec = &evt->evt.gap_evt.params.conn_sec_update.conn_sec; diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.h b/libraries/Bluefruit52Lib/src/BLEConnection.h index 5a6495a1c..56b0fadaf 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.h +++ b/libraries/Bluefruit52Lib/src/BLEConnection.h @@ -57,7 +57,8 @@ class BLEConnection bool _paired; bool _hvc_received; - ble_gap_addr_t _peer_addr; + ble_gap_addr_t _peer_addr; // resolvable connect address + ble_gap_addr_t _bond_id_addr; // address stored as bonded SemaphoreHandle_t _hvn_sem; SemaphoreHandle_t _wrcmd_sem; @@ -105,15 +106,21 @@ class BLEConnection bool getWriteCmdPacket(void); bool waitForIndicateConfirm(void); - bool storeCccd(void); + bool saveCccd(void); + bool loadCccd(void); + bool loadKeys(bond_keys_t* bkeys); + /*------------------------------------------------------------------*/ /* INTERNAL USAGE ONLY * Although declare as public, it is meant to be invoked by internal code. *------------------------------------------------------------------*/ void _eventHandler(ble_evt_t* evt); + bool _saveLongTermKey(bond_keys_t const* bkeys); + bool _loadLongTermKey(bond_keys_t* bkeys); + friend class BLEPairing; }; diff --git a/libraries/Bluefruit52Lib/src/BLEGatt.cpp b/libraries/Bluefruit52Lib/src/BLEGatt.cpp index 48b67f590..04bce2ce0 100644 --- a/libraries/Bluefruit52Lib/src/BLEGatt.cpp +++ b/libraries/Bluefruit52Lib/src/BLEGatt.cpp @@ -142,7 +142,7 @@ void BLEGatt::_eventHandler(ble_evt_t* evt) // Save CCCD if paired if ( conn->paired() && (evt_id == BLE_GATTS_EVT_WRITE) && (req_handle == chr->handles().cccd_handle) ) { - conn->storeCccd(); + conn->saveCccd(); } } } diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.cpp b/libraries/Bluefruit52Lib/src/BLEPairing.cpp index bf7a5a6c1..afdcdb633 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.cpp +++ b/libraries/Bluefruit52Lib/src/BLEPairing.cpp @@ -128,7 +128,6 @@ bool BLEPairing::resolveAddress(ble_gap_addr_t const * p_addr, ble_gap_irk_t con swap_endian(ecb_data.cleartext, SOC_ECB_CLEARTEXT_LENGTH); // compute using HW AES peripherals - // TODO use CC310 to compute AES (void) sd_ecb_block_encrypt(&ecb_data); // Swap output endian @@ -351,13 +350,7 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) LOG_LV2("PAIR", "Ediv = 0x%02X", _ediv); LOG_LV2_BUFFER("Rand", _bond_keys->own_enc.master_id.rand, 8); - //PRINT_INT(_bond_keys->peer_id.id_addr_info.addr_type); - //Serial.printBufferReverse(_bond_keys->peer_id.id_addr_info.addr, 6, ':'); - //Serial.println(); - - bond_save_keys(conn->getRole(), conn_hdl, _bond_keys); - -// _paired = true; + conn->_saveLongTermKey(_bond_keys); } rtos_free(_bond_keys); @@ -375,23 +368,13 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) // - Else return NULL --> Initiate key exchange ble_gap_evt_sec_info_request_t* sec_info = (ble_gap_evt_sec_info_request_t*) &evt->evt.gap_evt.params.sec_info_request; - LOG_LV2("PAIR", "Addr ID = %d, Addr Type = 0x%02X, ediv = 0x%02X", - sec_info->peer_addr.addr_id_peer, sec_info->peer_addr.addr_type, sec_info->master_id.ediv); + LOG_LV2("PAIR", "Addr ID = %d, Addr Type = 0x%02X", sec_info->peer_addr.addr_id_peer, sec_info->peer_addr.addr_type); LOG_LV2_BUFFER("Address", sec_info->peer_addr.addr, 6); - LOG_LV2_BUFFER("Rand", sec_info->master_id.rand, 8); bond_keys_t bkeys; - varclr(&bkeys); - - // TODO Random Static - // Resolvable - - - if ( bond_load_keys(conn->getRole(), sec_info->master_id.ediv, &bkeys) ) + if ( conn->_loadLongTermKey(&bkeys) ) { -// PRINT_INT(resolveAddress(&sec_info->peer_addr, &bkeys.peer_id.id_info)); - sd_ble_gap_sec_info_reply(conn_hdl, &bkeys.own_enc.enc_info, &bkeys.peer_id.id_info, NULL); _ediv = bkeys.own_enc.master_id.ediv; @@ -412,7 +395,7 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) { // Previously bonded --> secure by re-connection process --> Load & Set SysAttr (Apply Service Context) // Else Init SysAttr (first bonded) - if ( !bond_load_cccd(conn->getRole(), conn_hdl, _ediv) ) + if ( !conn->loadCccd() ) { sd_ble_gatts_sys_attr_set(conn_hdl, NULL, 0, 0); } diff --git a/libraries/Bluefruit52Lib/src/utility/bonding.cpp b/libraries/Bluefruit52Lib/src/utility/bonding.cpp index 5d402ff08..653f633e4 100644 --- a/libraries/Bluefruit52Lib/src/utility/bonding.cpp +++ b/libraries/Bluefruit52Lib/src/utility/bonding.cpp @@ -60,11 +60,12 @@ using namespace Adafruit_LittleFS_Namespace; * Each field has an 1-byte preceding length *------------------------------------------------------------------*/ #define SVC_CONTEXT_FLAG (BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS | BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS) -#define BOND_FNAME_LEN (max(sizeof(BOND_FNAME_PRPH), sizeof(BOND_FNAME_CNTR)) + 8)// TODO refactor later +#define BOND_FNAME_LEN max(sizeof(BOND_FNAME_PRPH), sizeof(BOND_FNAME_CNTR)) -static void get_fname (char* fname, uint8_t role, uint16_t ediv) +static void get_fname (char* fname, uint8_t role, uint8_t const mac[6]) { - sprintf(fname, (role == BLE_GAP_ROLE_PERIPH) ? BOND_FNAME_PRPH : BOND_FNAME_CNTR, ediv); + sprintf(fname, (role == BLE_GAP_ROLE_PERIPH) ? BOND_FNAME_PRPH : BOND_FNAME_CNTR, + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } static bool bdata_skip_field(File* file) @@ -94,18 +95,14 @@ void bond_init(void) /*------------------------------------------------------------------*/ /* Keys *------------------------------------------------------------------*/ -static void bond_save_keys_dfr (uint8_t role, uint16_t conn_hdl, bool lesc, bond_keys_t* bkeys) +static void bond_save_keys_dfr (uint8_t role, uint16_t conn_hdl, bond_keys_t* bkeys) { uint16_t const ediv = (role == BLE_GAP_ROLE_PERIPH) ? bkeys->own_enc.master_id.ediv : bkeys->peer_enc.master_id.ediv; + uint8_t const * mac = bkeys->peer_id.id_addr_info.addr; // Bond store keys using peer mac address e.g 1a2b3c4d5e6f - char filename[BOND_FNAME_LEN]; -// get_fname(filename, role, ediv); - - uint8_t const * mac = bkeys->peer_id.id_addr_info.addr; - sprintf(filename, BOND_DIR_PRPH "/%02X%02X%02X%02X%02X%02X", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + get_fname(filename, role, mac); // delete if file already exists if ( InternalFS.exists(filename) ) InternalFS.remove(filename); @@ -152,19 +149,26 @@ bool bond_load_keys(uint8_t role, ble_gap_addr_t* addr, bond_keys_t* bkeys) // Address is used as identity char filename[BOND_FNAME_LEN]; - // get_fname(filename, role, ediv); - sprintf(filename, BOND_DIR_PRPH "/%02X%02X%02X%02X%02X%02X", - addr->addr[0], addr->addr[1], addr->addr[2], addr->addr[3], addr->addr[4], addr->addr[5]); + get_fname(filename, role, addr->addr); File file(InternalFS); - VERIFY( file.open(filename, FILE_O_READ) ); - BOND_LOG("Loaded keys from file %s", filename); + if( file.open(filename, FILE_O_READ) ) + { + int keylen = file.read(); + file.read((uint8_t*) bkeys, keylen); + + ret = true; + BOND_LOG("Loaded keys from file %s", filename); + } + + file.close(); } break; case BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE: { // Resolvable address, we have to go through the whole list to perform IRK Address matching + char const * dpath = (role == BLE_GAP_ROLE_PERIPH ? BOND_DIR_PRPH : BOND_DIR_CNTR); File dir(dpath, FILE_O_READ, InternalFS); File file(InternalFS); @@ -177,8 +181,8 @@ bool bond_load_keys(uint8_t role, ble_gap_addr_t* addr, bond_keys_t* bkeys) file.read((uint8_t*) bkeys, keylen); if ( Bluefruit.Pairing.resolveAddress(addr, &bkeys->peer_id.id_info) ) { - BOND_LOG("Loaded keys from file %s/%s", dpath, file.name()); ret = true; + BOND_LOG("Loaded keys from file %s/%s", dpath, file.name()); } } @@ -199,7 +203,7 @@ bool bond_load_keys(uint8_t role, ble_gap_addr_t* addr, bond_keys_t* bkeys) /*------------------------------------------------------------------*/ /* CCCD *------------------------------------------------------------------*/ -static void bond_save_cccd_dfr (uint8_t role, uint16_t conn_hdl, uint16_t ediv) +static void bond_save_cccd_dfr (uint8_t role, uint16_t conn_hdl, ble_gap_addr_t const* id_addr) { uint16_t len=0; sd_ble_gatts_sys_attr_get(conn_hdl, NULL, &len, SVC_CONTEXT_FLAG); @@ -209,7 +213,7 @@ static void bond_save_cccd_dfr (uint8_t role, uint16_t conn_hdl, uint16_t ediv) VERIFY_STATUS(sd_ble_gatts_sys_attr_get(conn_hdl, sys_attr, &len, SVC_CONTEXT_FLAG),); char filename[BOND_FNAME_LEN]; - get_fname(filename, role, ediv); + get_fname(filename, role, id_addr->addr); File file(filename, FILE_O_WRITE, InternalFS); VERIFY(file,); @@ -225,53 +229,42 @@ static void bond_save_cccd_dfr (uint8_t role, uint16_t conn_hdl, uint16_t ediv) file.close(); } -bool bond_save_cccd (uint8_t role, uint16_t conn_hdl, uint16_t ediv) +bool bond_save_cccd (uint8_t role, uint16_t conn_hdl, ble_gap_addr_t const* id_addr) { - VERIFY(ediv != 0xFFFF); - // queue to execute in Ada Callback thread - return ada_callback(NULL, 0, bond_save_cccd_dfr, role, conn_hdl, ediv); + return ada_callback(id_addr, sizeof(ble_gap_addr_t), bond_save_cccd_dfr, role, conn_hdl, id_addr); } -bool bond_load_cccd(uint8_t role, uint16_t conn_hdl, uint16_t ediv) +bool bond_load_cccd(uint8_t role, uint16_t conn_hdl, ble_gap_addr_t const* id_addr) { bool loaded = false; - if ( ediv != 0xFFFF ) - { - char filename[BOND_FNAME_LEN]; - get_fname(filename, role, ediv); + char filename[BOND_FNAME_LEN]; + get_fname(filename, role, id_addr->addr); - File file(filename, FILE_O_READ, InternalFS); + File file(filename, FILE_O_READ, InternalFS); + if ( file ) + { + bdata_skip_field(&file); // skip key + bdata_skip_field(&file); // skip name - if ( file ) + int len = file.read(); + if ( len > 0 ) { - bdata_skip_field(&file); // skip key - bdata_skip_field(&file); // skip name + uint8_t sys_attr[len]; + file.read(sys_attr, len); - int len = file.read(); - if ( len > 0 ) + if ( ERROR_NONE == sd_ble_gatts_sys_attr_set(conn_hdl, sys_attr, len, SVC_CONTEXT_FLAG) ) { - uint8_t sys_attr[len]; - - file.read(sys_attr, len); - - if ( ERROR_NONE == sd_ble_gatts_sys_attr_set(conn_hdl, sys_attr, len, SVC_CONTEXT_FLAG) ) - { - loaded = true; - BOND_LOG("Loaded CCCD from file %s ( offset = %ld, len = %d bytes )", filename, file.size() - (len + 1), len); - } + loaded = true; + BOND_LOG("Loaded CCCD from file %s ( offset = %ld, len = %d bytes )", filename, file.size() - (len + 1), len); } } - - file.close(); } - if ( !loaded ) - { - LOG_LV1("BOND", "CCCD setting not found"); - } + file.close(); + if ( !loaded ) LOG_LV1("BOND", "CCCD setting not found"); return loaded; } @@ -378,8 +371,8 @@ void bond_clear_all(void) void bond_remove_key(uint8_t role, uint16_t ediv) { - char filename[BOND_FNAME_LEN]; - get_fname(filename, role, ediv); - - InternalFS.remove(filename); +// char filename[BOND_FNAME_LEN]; +// get_fname(filename, role, ediv); +// +// InternalFS.remove(filename); } diff --git a/libraries/Bluefruit52Lib/src/utility/bonding.h b/libraries/Bluefruit52Lib/src/utility/bonding.h index 396b9797f..926a45208 100644 --- a/libraries/Bluefruit52Lib/src/utility/bonding.h +++ b/libraries/Bluefruit52Lib/src/utility/bonding.h @@ -41,8 +41,8 @@ #define BOND_DIR_PRPH "/adafruit/bond_prph" #define BOND_DIR_CNTR "/adafruit/bond_cntr" -#define BOND_FNAME_PRPH BOND_DIR_PRPH "/%04x" -#define BOND_FNAME_CNTR BOND_DIR_CNTR "/%04x" +#define BOND_FNAME_PRPH BOND_DIR_PRPH "/%02X%02X%02X%02X%02X%02X" +#define BOND_FNAME_CNTR BOND_DIR_CNTR "/%02X%02X%02X%02X%02X%02X" // Shared keys with bonded device, size = 80 bytes typedef struct @@ -57,13 +57,13 @@ void bond_clear_prph(void); void bond_clear_cntr(void); void bond_clear_all(void); -void bond_remove_key(uint8_t role, uint16_t ediv); +void bond_remove_key(uint8_t role, uint16_t ediv) TU_ATTR_DEPRECATED("FIXME remove key"); bool bond_save_keys (uint8_t role, uint16_t conn_hdl, bond_keys_t const* bkeys); bool bond_load_keys(uint8_t role, ble_gap_addr_t*, bond_keys_t* bkeys); -bool bond_save_cccd (uint8_t role, uint16_t conn_hdl, uint16_t ediv); -bool bond_load_cccd (uint8_t role, uint16_t conn_hdl, uint16_t ediv); +bool bond_save_cccd (uint8_t role, uint16_t conn_hdl, ble_gap_addr_t const* id_addr); +bool bond_load_cccd (uint8_t role, uint16_t conn_hdl, ble_gap_addr_t const* id_addr); void bond_print_list(uint8_t role); From d32aa2c04cffb82a99e6c98cae74b7b09a25dcb0 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 14 Mar 2020 14:01:35 +0700 Subject: [PATCH 28/74] move bond_keys and peer_pubkey into BLEPairing change to use static variable instead of malloc pointer for more reliability --- .../Bluefruit52Lib/src/BLEConnection.cpp | 5 -- libraries/Bluefruit52Lib/src/BLEConnection.h | 3 - libraries/Bluefruit52Lib/src/BLEPairing.cpp | 63 +++++++------------ libraries/Bluefruit52Lib/src/BLEPairing.h | 7 ++- 4 files changed, 26 insertions(+), 52 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.cpp b/libraries/Bluefruit52Lib/src/BLEConnection.cpp index 9d8f7bbb8..f7bf291df 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.cpp +++ b/libraries/Bluefruit52Lib/src/BLEConnection.cpp @@ -61,8 +61,6 @@ BLEConnection::BLEConnection(uint16_t conn_hdl, ble_gap_evt_connected_t const* e _pair_sem = NULL; _ediv = 0xFFFF; - _bond_keys = NULL; - _peer_pubkey = NULL; } BLEConnection::~BLEConnection() @@ -73,9 +71,6 @@ BLEConnection::~BLEConnection() //------------- on-the-fly data must be freed -------------// if (_hvc_sem ) vSemaphoreDelete(_hvc_sem ); if (_pair_sem ) vSemaphoreDelete(_pair_sem); - - if (_bond_keys ) rtos_free(_bond_keys); - if (_peer_pubkey ) rtos_free(_peer_pubkey); } uint16_t BLEConnection::handle (void) diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.h b/libraries/Bluefruit52Lib/src/BLEConnection.h index 56b0fadaf..88174a1a2 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.h +++ b/libraries/Bluefruit52Lib/src/BLEConnection.h @@ -67,9 +67,6 @@ class BLEConnection SemaphoreHandle_t _hvc_sem; SemaphoreHandle_t _pair_sem; - bond_keys_t* _bond_keys; // Shared keys with bonded device, size ~ 80 bytes - uint8_t* _peer_pubkey; // LESC Peer public key - public: BLEConnection(uint16_t conn_hdl, ble_gap_evt_connected_t const * evt_connected, uint8_t hvn_qsize, uint8_t wrcmd_qsize); virtual ~BLEConnection(); diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.cpp b/libraries/Bluefruit52Lib/src/BLEPairing.cpp index afdcdb633..f0931896a 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.cpp +++ b/libraries/Bluefruit52Lib/src/BLEPairing.cpp @@ -67,7 +67,6 @@ BLEPairing::BLEPairing(void) #endif _ediv = EDIV_INVALID; - _bond_keys = NULL; _display_cb = NULL; _complete_cb = NULL; @@ -84,20 +83,20 @@ bool BLEPairing::begin(void) _private_key.begin(CRYS_ECPKI_DomainID_secp256r1); // init public key - nRFCrypto_ECC_PublicKey pubkey; - pubkey.begin(CRYS_ECPKI_DomainID_secp256r1); + nRFCrypto_ECC_PublicKey pubKey; + pubKey.begin(CRYS_ECPKI_DomainID_secp256r1); // Generate ECC Key pair - nRFCrypto_ECC::genKeyPair(_private_key, pubkey); + nRFCrypto_ECC::genKeyPair(_private_key, pubKey); // Convert to Raw bytes to response to LESC event - pubkey.toRaw(_pubkey_raw, sizeof(_pubkey_raw)); - pubkey.end(); + pubKey.toRaw(_pubkey, sizeof(_pubkey)); + pubKey.end(); // BLE use Little Endian, swap public key endian // Public Key = 32-byte N1 + 32-byte N2 - swap_endian(_pubkey_raw+1, 32); - swap_endian(_pubkey_raw+1+32, 32); + swap_endian(_pubkey+1, 32); + swap_endian(_pubkey+1+32, 32); #endif return true; @@ -225,18 +224,7 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) { case BLE_GAP_EVT_SEC_PARAMS_REQUEST: { - // Pairing in progress, Peer asking for our info - _bond_keys = rtos_malloc_type(bond_keys_t); - VERIFY(_bond_keys, ); - memclr(_bond_keys, sizeof(bond_keys_t)); - - // storing peer public key in connection - if (!conn->_peer_pubkey) - { - conn->_peer_pubkey = (uint8_t*) rtos_malloc(1+BLE_GAP_LESC_P256_PK_LEN); - } - VERIFY(conn->_peer_pubkey, ); - + // Pairing is started, Peer is asking for our info _ediv = EDIV_INVALID; /* Step 1: Pairing/Bonding @@ -251,17 +239,17 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) ble_gap_sec_keyset_t keyset = { .keys_own = { - .p_enc_key = &_bond_keys->own_enc, + .p_enc_key = &_bond_keys.own_enc, .p_id_key = NULL, .p_sign_key = NULL, - .p_pk = (ble_gap_lesc_p256_pk_t*) (_pubkey_raw+1) + .p_pk = (ble_gap_lesc_p256_pk_t*) (_pubkey+1) }, .keys_peer = { - .p_enc_key = &_bond_keys->peer_enc, - .p_id_key = &_bond_keys->peer_id, + .p_enc_key = &_bond_keys.peer_enc, + .p_id_key = &_bond_keys.peer_id, .p_sign_key = NULL, - .p_pk = (ble_gap_lesc_p256_pk_t*) (conn->_peer_pubkey+1) + .p_pk = (ble_gap_lesc_p256_pk_t*) (_peer_pubkey+1) } }; @@ -303,17 +291,16 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) // Raw public key from peer device is uncompressed // _peer_pubkey + 1 == dhkey_req->p_pk_peer->pk - uint8_t* peer_pubkey = conn->_peer_pubkey; - peer_pubkey[0] = CRYS_EC_PointUncompressed; + _peer_pubkey[0] = CRYS_EC_PointUncompressed; // Swap Endian data from air - swap_endian(peer_pubkey+1 , 32); - swap_endian(peer_pubkey+1+32, 32); + swap_endian(_peer_pubkey+1 , 32); + swap_endian(_peer_pubkey+1+32, 32); // Create nRFCrypto pubkey from raw format nRFCrypto_ECC_PublicKey peerPublickKey; peerPublickKey.begin(CRYS_ECPKI_DomainID_secp256r1); - peerPublickKey.fromRaw(peer_pubkey, 1+BLE_GAP_LESC_P256_PK_LEN); + peerPublickKey.fromRaw(_peer_pubkey, 1+BLE_GAP_LESC_P256_PK_LEN); // Create shared secret derivation primitive using ECC Diffie-Hellman ble_gap_lesc_dhkey_t dhkey; @@ -325,8 +312,8 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) swap_endian(dhkey.key, 32); // Swap back the peer pubkey since SoftDevice still need this until Authentication is complete - swap_endian(peer_pubkey+1 , 32); - swap_endian(peer_pubkey+1+32, 32); + swap_endian(_peer_pubkey+1 , 32); + swap_endian(_peer_pubkey+1+32, 32); sd_ble_gap_lesc_dhkey_reply(conn_hdl, &dhkey); } @@ -340,22 +327,16 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) LOG_LV2("PAIR", "Auth Status = 0x%02X, Bonded = %d, LESC = %d, Our Kdist = 0x%02X, Peer Kdist = 0x%02X ", status->auth_status, status->bonded, status->lesc, *((uint8_t*) &status->kdist_own), *((uint8_t*) &status->kdist_peer)); - rtos_free(conn->_peer_pubkey); - conn->_peer_pubkey = NULL; - // Pairing succeeded --> save encryption keys ( Bonding ) if (BLE_GAP_SEC_STATUS_SUCCESS == status->auth_status) { - _ediv = _bond_keys->own_enc.master_id.ediv; + _ediv = _bond_keys.own_enc.master_id.ediv; LOG_LV2("PAIR", "Ediv = 0x%02X", _ediv); - LOG_LV2_BUFFER("Rand", _bond_keys->own_enc.master_id.rand, 8); + LOG_LV2_BUFFER("Rand", _bond_keys.own_enc.master_id.rand, 8); - conn->_saveLongTermKey(_bond_keys); + conn->_saveLongTermKey(&_bond_keys); } - rtos_free(_bond_keys); - _bond_keys = NULL; - // Invoke callback if (_complete_cb) ada_callback(NULL, 0, _complete_cb, conn_hdl, status->auth_status); } diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.h b/libraries/Bluefruit52Lib/src/BLEPairing.h index 9c716cb92..abd898f25 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.h +++ b/libraries/Bluefruit52Lib/src/BLEPairing.h @@ -65,10 +65,11 @@ class BLEPairing nRFCrypto_ECC_PrivateKey _private_key; - uint8_t _pubkey_raw[1+BLE_GAP_LESC_P256_PK_LEN]; // raw key: 1 header + 64 data + uint8_t _pubkey[1+BLE_GAP_LESC_P256_PK_LEN]; // our public key: 1 header + 64 data + uint8_t _peer_pubkey[1+BLE_GAP_LESC_P256_PK_LEN]; // peer public key when using LESC - uint16_t _ediv; - bond_keys_t* _bond_keys; // Shared keys with bonded device, size ~ 80 bytes + bond_keys_t _bond_keys; // Shared keys with bonded device during securing connection, size ~ 80 bytes + uint16_t _ediv; pair_display_cb_t _display_cb; pair_complete_cb_t _complete_cb; From 4653f9cdc387adbce968c89577a7ad2bb404ce33 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 14 Mar 2020 14:07:31 +0700 Subject: [PATCH 29/74] save key dfr don't need malloc --- libraries/Bluefruit52Lib/src/utility/bonding.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/utility/bonding.cpp b/libraries/Bluefruit52Lib/src/utility/bonding.cpp index 653f633e4..cf26812c6 100644 --- a/libraries/Bluefruit52Lib/src/utility/bonding.cpp +++ b/libraries/Bluefruit52Lib/src/utility/bonding.cpp @@ -95,7 +95,7 @@ void bond_init(void) /*------------------------------------------------------------------*/ /* Keys *------------------------------------------------------------------*/ -static void bond_save_keys_dfr (uint8_t role, uint16_t conn_hdl, bond_keys_t* bkeys) +static void bond_save_keys_dfr (uint8_t role, uint16_t conn_hdl, bond_keys_t const * bkeys) { uint16_t const ediv = (role == BLE_GAP_ROLE_PERIPH) ? bkeys->own_enc.master_id.ediv : bkeys->peer_enc.master_id.ediv; uint8_t const * mac = bkeys->peer_id.id_addr_info.addr; @@ -133,7 +133,7 @@ static void bond_save_keys_dfr (uint8_t role, uint16_t conn_hdl, bond_keys_t* bk bool bond_save_keys (uint8_t role, uint16_t conn_hdl, bond_keys_t const* bkeys) { // queue to execute in Ada Callback thread - return ada_callback(bkeys, sizeof(bond_keys_t), bond_save_keys_dfr, role, conn_hdl, bkeys); + return ada_callback(NULL, 0, bond_save_keys_dfr, role, conn_hdl, bkeys); } bool bond_load_keys(uint8_t role, ble_gap_addr_t* addr, bond_keys_t* bkeys) From 278f82aefe5b44563e2cd464f4bbb154ef546839 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 14 Mar 2020 14:27:56 +0700 Subject: [PATCH 30/74] enhance save cccd, only write to flash if contents not matched --- .../Bluefruit52Lib/src/utility/bonding.cpp | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/utility/bonding.cpp b/libraries/Bluefruit52Lib/src/utility/bonding.cpp index cf26812c6..125962a9d 100644 --- a/libraries/Bluefruit52Lib/src/utility/bonding.cpp +++ b/libraries/Bluefruit52Lib/src/utility/bonding.cpp @@ -155,10 +155,13 @@ bool bond_load_keys(uint8_t role, ble_gap_addr_t* addr, bond_keys_t* bkeys) if( file.open(filename, FILE_O_READ) ) { int keylen = file.read(); - file.read((uint8_t*) bkeys, keylen); + if ( keylen > 0 ) + { + file.read((uint8_t*) bkeys, keylen); - ret = true; - BOND_LOG("Loaded keys from file %s", filename); + ret = true; + BOND_LOG("Loaded keys from file %s", filename); + } } file.close(); @@ -222,9 +225,26 @@ static void bond_save_cccd_dfr (uint8_t role, uint16_t conn_hdl, ble_gap_addr_t bdata_skip_field(&file); // skip key bdata_skip_field(&file); // skip name - bdata_write(&file, sys_attr, len); + // only write if there is any data changes + bool do_write = true; - BOND_LOG("Saved CCCD setting to file %s ( offset = %ld, len = %d bytes )", filename, file.size() - (len + 1), len); + if ( len == ((uint16_t) file.read()) ) + { + uint8_t old_data[len]; + file.read(old_data, len); + + if ( 0 == memcmp(sys_attr, old_data, len) ) + { + do_write = false; + BOND_LOG("CCCD matches file %s contents, no need to write", filename); + } + } + + if (do_write) + { + bdata_write(&file, sys_attr, len); + BOND_LOG("Saved CCCD to file %s ( offset = %ld, len = %d bytes )", filename, file.size() - (len + 1), len); + } file.close(); } From 5b16aee26d4f3c197dc5b8f4eb4990fe7dee9c90 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 14 Mar 2020 14:35:35 +0700 Subject: [PATCH 31/74] clean up --- libraries/Bluefruit52Lib/src/BLEConnection.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.h b/libraries/Bluefruit52Lib/src/BLEConnection.h index 88174a1a2..403782e5e 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.h +++ b/libraries/Bluefruit52Lib/src/BLEConnection.h @@ -117,8 +117,6 @@ class BLEConnection bool _saveLongTermKey(bond_keys_t const* bkeys); bool _loadLongTermKey(bond_keys_t* bkeys); - - friend class BLEPairing; }; From c6167bc4e58c72c1b4913b1db7a4de6ecccc4a09 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 14 Mar 2020 14:37:29 +0700 Subject: [PATCH 32/74] clean up --- libraries/Bluefruit52Lib/src/BLEPairing.cpp | 13 +++---------- libraries/Bluefruit52Lib/src/BLEPairing.h | 1 - 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.cpp b/libraries/Bluefruit52Lib/src/BLEPairing.cpp index f0931896a..97316c647 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.cpp +++ b/libraries/Bluefruit52Lib/src/BLEPairing.cpp @@ -66,8 +66,6 @@ BLEPairing::BLEPairing(void) // _sec_param.lesc = 1; // enable LESC if CryptoCell is present #endif - _ediv = EDIV_INVALID; - _display_cb = NULL; _complete_cb = NULL; } @@ -224,10 +222,8 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) { case BLE_GAP_EVT_SEC_PARAMS_REQUEST: { - // Pairing is started, Peer is asking for our info - _ediv = EDIV_INVALID; - - /* Step 1: Pairing/Bonding + /* Pairing is started, Peer is asking for our info + * Step 1: Pairing/Bonding * - Central supplies its parameters * - We replies with our security parameters */ @@ -330,8 +326,7 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) // Pairing succeeded --> save encryption keys ( Bonding ) if (BLE_GAP_SEC_STATUS_SUCCESS == status->auth_status) { - _ediv = _bond_keys.own_enc.master_id.ediv; - LOG_LV2("PAIR", "Ediv = 0x%02X", _ediv); + LOG_LV2("PAIR", "Ediv = 0x%02X", _bond_keys.own_enc.master_id.ediv); LOG_LV2_BUFFER("Rand", _bond_keys.own_enc.master_id.rand, 8); conn->_saveLongTermKey(&_bond_keys); @@ -357,8 +352,6 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) if ( conn->_loadLongTermKey(&bkeys) ) { sd_ble_gap_sec_info_reply(conn_hdl, &bkeys.own_enc.enc_info, &bkeys.peer_id.id_info, NULL); - - _ediv = bkeys.own_enc.master_id.ediv; } else { sd_ble_gap_sec_info_reply(conn_hdl, NULL, NULL, NULL); diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.h b/libraries/Bluefruit52Lib/src/BLEPairing.h index abd898f25..cc7ab040b 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.h +++ b/libraries/Bluefruit52Lib/src/BLEPairing.h @@ -69,7 +69,6 @@ class BLEPairing uint8_t _peer_pubkey[1+BLE_GAP_LESC_P256_PK_LEN]; // peer public key when using LESC bond_keys_t _bond_keys; // Shared keys with bonded device during securing connection, size ~ 80 bytes - uint16_t _ediv; pair_display_cb_t _display_cb; pair_complete_cb_t _complete_cb; From e6bcfcb4c09dfa0898fff7022b91c3af4f9184dc Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 14 Mar 2020 16:07:40 +0700 Subject: [PATCH 33/74] update bond remove keys --- libraries/Bluefruit52Lib/src/utility/bonding.cpp | 10 +++++----- libraries/Bluefruit52Lib/src/utility/bonding.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/utility/bonding.cpp b/libraries/Bluefruit52Lib/src/utility/bonding.cpp index 125962a9d..b9dd7dfde 100644 --- a/libraries/Bluefruit52Lib/src/utility/bonding.cpp +++ b/libraries/Bluefruit52Lib/src/utility/bonding.cpp @@ -389,10 +389,10 @@ void bond_clear_all(void) InternalFS.mkdir(BOND_DIR_CNTR); } -void bond_remove_key(uint8_t role, uint16_t ediv) +void bond_remove_key(uint8_t role, ble_gap_addr_t const* id_addr) { -// char filename[BOND_FNAME_LEN]; -// get_fname(filename, role, ediv); -// -// InternalFS.remove(filename); + char filename[BOND_FNAME_LEN]; + get_fname(filename, role, id_addr->addr); + + InternalFS.remove(filename); } diff --git a/libraries/Bluefruit52Lib/src/utility/bonding.h b/libraries/Bluefruit52Lib/src/utility/bonding.h index 926a45208..27bbb15f8 100644 --- a/libraries/Bluefruit52Lib/src/utility/bonding.h +++ b/libraries/Bluefruit52Lib/src/utility/bonding.h @@ -57,7 +57,7 @@ void bond_clear_prph(void); void bond_clear_cntr(void); void bond_clear_all(void); -void bond_remove_key(uint8_t role, uint16_t ediv) TU_ATTR_DEPRECATED("FIXME remove key"); +void bond_remove_key(uint8_t role, ble_gap_addr_t const* id_addr); bool bond_save_keys (uint8_t role, uint16_t conn_hdl, bond_keys_t const* bkeys); bool bond_load_keys(uint8_t role, ble_gap_addr_t*, bond_keys_t* bkeys); From b555131ca216fff9c303531a51e13a66d7117f99 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 14 Mar 2020 16:29:51 +0700 Subject: [PATCH 34/74] improve connection requestPairing() move loadCccd() to --- cores/nRF5/verify.h | 10 ++- .../Bluefruit52Lib/src/BLEConnection.cpp | 61 ++++++++++--------- libraries/Bluefruit52Lib/src/BLEConnection.h | 4 +- libraries/Bluefruit52Lib/src/BLEPairing.cpp | 16 +---- 4 files changed, 42 insertions(+), 49 deletions(-) diff --git a/cores/nRF5/verify.h b/cores/nRF5/verify.h index c66cb4b35..c5bcc53ad 100644 --- a/cores/nRF5/verify.h +++ b/cores/nRF5/verify.h @@ -107,9 +107,15 @@ extern "C" * - status value if called with 1 parameter e.g VERIFY_STATUS(status) * - 2 parameter if called with 2 parameters e.g VERIFY_STATUS(status, errorcode) */ -#define VERIFY_STATUS(...) _GET_3RD_ARG(__VA_ARGS__, VERIFY_ERR_2ARGS, VERIFY_ERR_1ARGS)(__VA_ARGS__, dbg_err_str) +#define VERIFY_STATUS(...) _GET_3RD_ARG(__VA_ARGS__, VERIFY_ERR_2ARGS, VERIFY_ERR_1ARGS)(__VA_ARGS__, dbg_err_str) -#define VERIFY_ERROR(...) _GET_3RD_ARG(__VA_ARGS__, VERIFY_ERR_2ARGS, VERIFY_ERR_1ARGS)(__VA_ARGS__, NULL) +#define PRINT_STATUS(_exp) do \ +{ \ + int32_t _status = (int32_t) _exp; \ + if ( 0 != _status ) VERIFY_MESS(_status, dbg_err_str); \ +} while(0) \ + +#define VERIFY_ERROR(...) _GET_3RD_ARG(__VA_ARGS__, VERIFY_ERR_2ARGS, VERIFY_ERR_1ARGS)(__VA_ARGS__, NULL) /*------------------------------------------------------------------*/ /* VERIFY diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.cpp b/libraries/Bluefruit52Lib/src/BLEConnection.cpp index f7bf291df..2dc8f7ae1 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.cpp +++ b/libraries/Bluefruit52Lib/src/BLEConnection.cpp @@ -263,44 +263,42 @@ bool BLEConnection::requestPairing(void) // on-the-fly semaphore _pair_sem = xSemaphoreCreateBinary(); + VERIFY(_pair_sem); - if ( _role == BLE_GAP_ROLE_PERIPH ) - { - VERIFY_STATUS( sd_ble_gap_authenticate(_conn_hdl, &sec_param ), false); - xSemaphoreTake(_pair_sem, portMAX_DELAY); - } - else - { - uint16_t cntr_ediv = 0xFFFF; - bond_keys_t bkeys; + bond_keys_t ltkeys; + uint32_t err; - // Check to see if we did bonded with current prph previously - // TODO currently only matches key using fixed address - if ( bond_find_cntr(&_peer_addr, &bkeys) ) - { - cntr_ediv = bkeys.peer_enc.master_id.ediv; - LOG_LV2("BOND", "Load Keys from file " BOND_FNAME_CNTR, cntr_ediv); - VERIFY_STATUS( sd_ble_gap_encrypt(_conn_hdl, &bkeys.peer_enc.master_id, &bkeys.peer_enc.enc_info), false); + if ( _loadLongTermKey(<keys) ) + { + // We already bonded with this peer previously + // Encrypt the connection using stored Longterm Key + err = sd_ble_gap_encrypt(_conn_hdl, <keys.peer_enc.master_id, <keys.peer_enc.enc_info); + PRINT_STATUS(err); - }else + if ( err == NRF_SUCCESS ) { - VERIFY_STATUS( sd_ble_gap_authenticate(_conn_hdl, &sec_param ), false); - } - - xSemaphoreTake(_pair_sem, portMAX_DELAY); + xSemaphoreTake(_pair_sem, portMAX_DELAY); - // Failed to pair using central stored keys, this happens when - // Prph delete bonds while we did not --> let's remove the obsolete keyfile and retry - if ( !_paired && (cntr_ediv != 0xffff) ) - { - // FIXME central remove key - bond_remove_key(BLE_GAP_ROLE_CENTRAL, cntr_ediv); + // Failed to pair using stored key, this happens when peer + // delete bonds while we did not --> let's remove the obsolete keyfile and retry + if ( !_paired ) + { + bond_remove_key(_role, <keys.peer_id.id_addr_info); - // Re-try with a fresh session - VERIFY_STATUS( sd_ble_gap_authenticate(_conn_hdl, &sec_param ), false); + // Re-try with a fresh session + err = sd_ble_gap_authenticate(_conn_hdl, &sec_param ); + PRINT_STATUS(err); - xSemaphoreTake(_pair_sem, portMAX_DELAY); + xSemaphoreTake(_pair_sem, portMAX_DELAY); + } } + }else + { + // start a fresh new authentication process + err = sd_ble_gap_authenticate(_conn_hdl, &sec_param ); + PRINT_STATUS(err); + + xSemaphoreTake(_pair_sem, portMAX_DELAY); } vSemaphoreDelete(_pair_sem); @@ -340,6 +338,9 @@ void BLEConnection::_eventHandler(ble_evt_t* evt) if ( !( conn_sec->sec_mode.sm == 1 && conn_sec->sec_mode.lv == 1) ) { _paired = true; + + // Try to restore CCCD with bonded peer, if it doesn't exist (newly bonded), initialize it + if ( !loadCccd() ) sd_ble_gatts_sys_attr_set(_conn_hdl, NULL, 0, 0); } if (_pair_sem) xSemaphoreGive(_pair_sem); diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.h b/libraries/Bluefruit52Lib/src/BLEConnection.h index 403782e5e..a082c008f 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.h +++ b/libraries/Bluefruit52Lib/src/BLEConnection.h @@ -115,8 +115,8 @@ class BLEConnection *------------------------------------------------------------------*/ void _eventHandler(ble_evt_t* evt); - bool _saveLongTermKey(bond_keys_t const* bkeys); - bool _loadLongTermKey(bond_keys_t* bkeys); + bool _saveLongTermKey(bond_keys_t const* ltkey); + bool _loadLongTermKey(bond_keys_t* ltkey); }; diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.cpp b/libraries/Bluefruit52Lib/src/BLEPairing.cpp index 97316c647..ce7affa60 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.cpp +++ b/libraries/Bluefruit52Lib/src/BLEPairing.cpp @@ -362,22 +362,8 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) case BLE_GAP_EVT_CONN_SEC_UPDATE: { const ble_gap_conn_sec_t* conn_sec = &evt->evt.gap_evt.params.conn_sec_update.conn_sec; + (void) conn_sec; LOG_LV2("PAIR", "Security Mode = %d, Level = %d", conn_sec->sec_mode.sm, conn_sec->sec_mode.lv); - - // Connection is secured (paired) if encryption level > 1 - if ( !( conn_sec->sec_mode.sm == 1 && conn_sec->sec_mode.lv == 1) ) - { - // Previously bonded --> secure by re-connection process --> Load & Set SysAttr (Apply Service Context) - // Else Init SysAttr (first bonded) - if ( !conn->loadCccd() ) - { - sd_ble_gatts_sys_attr_set(conn_hdl, NULL, 0, 0); - } - -// _paired = true; - } - -// if (_pair_sem) xSemaphoreGive(_pair_sem); } break; From 1a9415005bddaa92bca573b34e7e18fc04d26ffd Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 14 Mar 2020 16:43:16 +0700 Subject: [PATCH 35/74] clean up bonding code --- .../Bluefruit52Lib/src/utility/bonding.cpp | 38 ------------------- .../Bluefruit52Lib/src/utility/bonding.h | 6 +-- 2 files changed, 1 insertion(+), 43 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/utility/bonding.cpp b/libraries/Bluefruit52Lib/src/utility/bonding.cpp index b9dd7dfde..2db8ef714 100644 --- a/libraries/Bluefruit52Lib/src/utility/bonding.cpp +++ b/libraries/Bluefruit52Lib/src/utility/bonding.cpp @@ -318,44 +318,6 @@ void bond_print_list(uint8_t role) dir.close(); } - -bool bond_find_cntr(ble_gap_addr_t const * addr, bond_keys_t* bkeys) -{ - bool found = false; - - File dir(BOND_DIR_CNTR, FILE_O_READ, InternalFS); - File file(InternalFS); - - while ( (file = dir.openNextFile(FILE_O_READ)) ) - { - // Read bond data of each stored file - int keylen = file.read(); - if ( keylen == sizeof(bond_keys_t) ) - { - file.read((uint8_t*) bkeys, keylen); - - // Compare static address - if ( !memcmp(addr->addr, bkeys->peer_id.id_addr_info.addr, 6) ) - { - found = true; - } - else if ( addr->addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE ) - { - // Resolving private address - } - } - - file.close(); - - if ( found ) break; - } - - file.close(); - dir.close(); - - return found; -} - /*------------------------------------------------------------------*/ /* DELETE *------------------------------------------------------------------*/ diff --git a/libraries/Bluefruit52Lib/src/utility/bonding.h b/libraries/Bluefruit52Lib/src/utility/bonding.h index 27bbb15f8..f6c4dfb98 100644 --- a/libraries/Bluefruit52Lib/src/utility/bonding.h +++ b/libraries/Bluefruit52Lib/src/utility/bonding.h @@ -60,15 +60,11 @@ void bond_clear_all(void); void bond_remove_key(uint8_t role, ble_gap_addr_t const* id_addr); bool bond_save_keys (uint8_t role, uint16_t conn_hdl, bond_keys_t const* bkeys); -bool bond_load_keys(uint8_t role, ble_gap_addr_t*, bond_keys_t* bkeys); +bool bond_load_keys(uint8_t role, ble_gap_addr_t* peer_addr, bond_keys_t* bkeys); bool bond_save_cccd (uint8_t role, uint16_t conn_hdl, ble_gap_addr_t const* id_addr); bool bond_load_cccd (uint8_t role, uint16_t conn_hdl, ble_gap_addr_t const* id_addr); void bond_print_list(uint8_t role); -bool bond_find_cntr(ble_gap_addr_t const * addr, bond_keys_t* bkeys); - - - #endif /* BONDING_H_ */ From 0ee2124e063b4f422d6c611102178f951af45003 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 14 Mar 2020 16:45:50 +0700 Subject: [PATCH 36/74] clean up BLEConnection --- libraries/Bluefruit52Lib/src/BLEConnection.cpp | 13 +++---------- libraries/Bluefruit52Lib/src/BLEConnection.h | 9 +++------ libraries/Bluefruit52Lib/src/BLEPairing.cpp | 4 ++-- libraries/Bluefruit52Lib/src/services/BLEDfu.cpp | 3 +-- 4 files changed, 9 insertions(+), 20 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.cpp b/libraries/Bluefruit52Lib/src/BLEConnection.cpp index 2dc8f7ae1..4497f027d 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.cpp +++ b/libraries/Bluefruit52Lib/src/BLEConnection.cpp @@ -232,7 +232,7 @@ bool BLEConnection::loadCccd(void) return bond_load_cccd(_role, _conn_hdl, &_bond_id_addr); } -bool BLEConnection::_saveLongTermKey(bond_keys_t const* ltkey) +bool BLEConnection::saveLongTermKey(bond_keys_t const* ltkey) { bond_save_keys(_role, _conn_hdl, ltkey); _bond_id_addr = ltkey->peer_id.id_addr_info; @@ -240,20 +240,13 @@ bool BLEConnection::_saveLongTermKey(bond_keys_t const* ltkey) return true; } -bool BLEConnection::_loadLongTermKey(bond_keys_t* ltkey) +bool BLEConnection::loadLongTermKey(bond_keys_t* ltkey) { VERIFY( bond_load_keys(_role, &_peer_addr, ltkey) ); _bond_id_addr = ltkey->peer_id.id_addr_info; return true; } -bool BLEConnection::loadKeys(bond_keys_t* bkeys) -{ - return false; - // FIXME dfu key sharing later - //return bond_load_keys(_role, _ediv, bkeys); -} - bool BLEConnection::requestPairing(void) { // skip if already paired @@ -268,7 +261,7 @@ bool BLEConnection::requestPairing(void) bond_keys_t ltkeys; uint32_t err; - if ( _loadLongTermKey(<keys) ) + if ( loadLongTermKey(<keys) ) { // We already bonded with this peer previously // Encrypt the connection using stored Longterm Key diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.h b/libraries/Bluefruit52Lib/src/BLEConnection.h index a082c008f..80b99b5c5 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.h +++ b/libraries/Bluefruit52Lib/src/BLEConnection.h @@ -103,20 +103,17 @@ class BLEConnection bool getWriteCmdPacket(void); bool waitForIndicateConfirm(void); + bool saveLongTermKey(bond_keys_t const* ltkey); + bool loadLongTermKey(bond_keys_t* ltkey); + bool saveCccd(void); bool loadCccd(void); - bool loadKeys(bond_keys_t* bkeys); - - /*------------------------------------------------------------------*/ /* INTERNAL USAGE ONLY * Although declare as public, it is meant to be invoked by internal code. *------------------------------------------------------------------*/ void _eventHandler(ble_evt_t* evt); - - bool _saveLongTermKey(bond_keys_t const* ltkey); - bool _loadLongTermKey(bond_keys_t* ltkey); }; diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.cpp b/libraries/Bluefruit52Lib/src/BLEPairing.cpp index ce7affa60..96b258838 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.cpp +++ b/libraries/Bluefruit52Lib/src/BLEPairing.cpp @@ -329,7 +329,7 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) LOG_LV2("PAIR", "Ediv = 0x%02X", _bond_keys.own_enc.master_id.ediv); LOG_LV2_BUFFER("Rand", _bond_keys.own_enc.master_id.rand, 8); - conn->_saveLongTermKey(&_bond_keys); + conn->saveLongTermKey(&_bond_keys); } // Invoke callback @@ -349,7 +349,7 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) bond_keys_t bkeys; - if ( conn->_loadLongTermKey(&bkeys) ) + if ( conn->loadLongTermKey(&bkeys) ) { sd_ble_gap_sec_info_reply(conn_hdl, &bkeys.own_enc.enc_info, &bkeys.peer_id.id_info, NULL); } else diff --git a/libraries/Bluefruit52Lib/src/services/BLEDfu.cpp b/libraries/Bluefruit52Lib/src/services/BLEDfu.cpp index 400e92fef..675145be7 100644 --- a/libraries/Bluefruit52Lib/src/services/BLEDfu.cpp +++ b/libraries/Bluefruit52Lib/src/services/BLEDfu.cpp @@ -140,8 +140,7 @@ static void bledfu_control_wr_authorize_cb(uint16_t conn_hdl, BLECharacteristic* if ( conn->paired() ) { bond_keys_t bkeys; - - if ( conn->loadKeys(&bkeys) ) + if ( conn->loadLongTermKey(&bkeys) ) { peer_data->addr = bkeys.peer_id.id_addr_info; peer_data->irk = bkeys.peer_id.id_info; From b487db96032321e79a1b5e6c683d1f71d4af0eaa Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 16 Mar 2020 13:22:13 +0700 Subject: [PATCH 37/74] rename display callback to passkey callback --- .../pairing_display/pairing_display.ino | 2 +- libraries/Bluefruit52Lib/src/BLEConnection.cpp | 2 ++ libraries/Bluefruit52Lib/src/BLEPairing.cpp | 17 ++++------------- libraries/Bluefruit52Lib/src/BLEPairing.h | 6 +++--- .../Bluefruit52Lib/src/utility/bonding.cpp | 1 - 5 files changed, 10 insertions(+), 18 deletions(-) diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino index 635bdd42f..18ce8fe0c 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino @@ -116,7 +116,7 @@ void setup() Bluefruit.setName("Bluefruit52"); // Serial.println("Setting pairing PIN to: " PAIRING_PIN); - Bluefruit.Pairing.setDisplayCallback(pairing_display_callback); + Bluefruit.Pairing.setPasskeyCallback(pairing_display_callback); Bluefruit.Pairing.setCompleteCallback(pairing_complete_callback); Bluefruit.Periph.setConnectCallback(connect_callback); diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.cpp b/libraries/Bluefruit52Lib/src/BLEConnection.cpp index 4497f027d..9c41fd0d7 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.cpp +++ b/libraries/Bluefruit52Lib/src/BLEConnection.cpp @@ -325,7 +325,9 @@ void BLEConnection::_eventHandler(ble_evt_t* evt) case BLE_GAP_EVT_CONN_SEC_UPDATE: { + // Connection is secured, we have paired/bonded const ble_gap_conn_sec_t* conn_sec = &evt->evt.gap_evt.params.conn_sec_update.conn_sec; + LOG_LV2("PAIR", "Security Mode = %d, Level = %d", conn_sec->sec_mode.sm, conn_sec->sec_mode.lv); // Connection is secured (paired) if encryption level > 1 if ( !( conn_sec->sec_mode.sm == 1 && conn_sec->sec_mode.lv == 1) ) diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.cpp b/libraries/Bluefruit52Lib/src/BLEPairing.cpp index 96b258838..d348c1be9 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.cpp +++ b/libraries/Bluefruit52Lib/src/BLEPairing.cpp @@ -66,7 +66,7 @@ BLEPairing::BLEPairing(void) // _sec_param.lesc = 1; // enable LESC if CryptoCell is present #endif - _display_cb = NULL; + _passkey_cb = NULL; _complete_cb = NULL; } @@ -165,9 +165,9 @@ bool BLEPairing::setPIN(const char* pin) } // Pairing using LESC with peripheral display -bool BLEPairing::setDisplayCallback(pair_display_cb_t fp) +bool BLEPairing::setPasskeyCallback(pair_passkey_cb_t fp) { - _display_cb = fp; + _passkey_cb = fp; if ( fp == NULL ) { @@ -266,7 +266,7 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) LOG_LV2("PAIR", "Passkey = %.6s, match request = %d", passkey_display->passkey, passkey_display->match_request); // Invoke display callback - if ( _display_cb ) ada_callback(passkey_display->passkey, 6, _display_cb, conn_hdl, passkey_display->passkey); + if ( _passkey_cb ) ada_callback(passkey_display->passkey, 6, _passkey_cb, conn_hdl, passkey_display->passkey); if (passkey_display->match_request) { @@ -359,15 +359,6 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) } break; - case BLE_GAP_EVT_CONN_SEC_UPDATE: - { - const ble_gap_conn_sec_t* conn_sec = &evt->evt.gap_evt.params.conn_sec_update.conn_sec; - (void) conn_sec; - LOG_LV2("PAIR", "Security Mode = %d, Level = %d", conn_sec->sec_mode.sm, conn_sec->sec_mode.lv); - } - break; - - default: break; } } diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.h b/libraries/Bluefruit52Lib/src/BLEPairing.h index cc7ab040b..27b2e8762 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.h +++ b/libraries/Bluefruit52Lib/src/BLEPairing.h @@ -35,7 +35,7 @@ class BLEPairing { public: - typedef void (*pair_display_cb_t ) (uint16_t conn_hdl, uint8_t const passkey[6]); + typedef void (*pair_passkey_cb_t ) (uint16_t conn_hdl, uint8_t const passkey[6]); typedef void (*pair_complete_cb_t) (uint16_t conn_hdl, uint8_t auth_status); BLEPairing(void); @@ -49,7 +49,7 @@ class BLEPairing bool resolveAddress(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * irk); //------------- Callbacks -------------// - bool setDisplayCallback(pair_display_cb_t fp); + bool setPasskeyCallback(pair_passkey_cb_t fp); void setCompleteCallback(pair_complete_cb_t fp); /*------------------------------------------------------------------*/ @@ -70,7 +70,7 @@ class BLEPairing bond_keys_t _bond_keys; // Shared keys with bonded device during securing connection, size ~ 80 bytes - pair_display_cb_t _display_cb; + pair_passkey_cb_t _passkey_cb; pair_complete_cb_t _complete_cb; }; diff --git a/libraries/Bluefruit52Lib/src/utility/bonding.cpp b/libraries/Bluefruit52Lib/src/utility/bonding.cpp index 2db8ef714..387bec16f 100644 --- a/libraries/Bluefruit52Lib/src/utility/bonding.cpp +++ b/libraries/Bluefruit52Lib/src/utility/bonding.cpp @@ -337,7 +337,6 @@ void bond_clear_cntr(void) // Create an empty one InternalFS.mkdir(BOND_DIR_CNTR); - } void bond_clear_all(void) From 7b432602aa3137fece3c8e1761378f592f35a3bf Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 16 Mar 2020 22:44:24 +0700 Subject: [PATCH 38/74] clean up --- .../Bluefruit52Lib/src/BLEConnection.cpp | 22 ++++++------------- libraries/Bluefruit52Lib/src/BLEPairing.cpp | 12 ++++++++++ libraries/Bluefruit52Lib/src/BLEPairing.h | 5 ++++- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.cpp b/libraries/Bluefruit52Lib/src/BLEConnection.cpp index 9c41fd0d7..59d473354 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.cpp +++ b/libraries/Bluefruit52Lib/src/BLEConnection.cpp @@ -252,23 +252,19 @@ bool BLEConnection::requestPairing(void) // skip if already paired if ( _paired ) return true; - ble_gap_sec_params_t sec_param = Bluefruit.Pairing.getSecureParam(); + BLEPairing* secure = &Bluefruit.Pairing; // on-the-fly semaphore _pair_sem = xSemaphoreCreateBinary(); VERIFY(_pair_sem); - bond_keys_t ltkeys; - uint32_t err; + bond_keys_t ltkey; - if ( loadLongTermKey(<keys) ) + if ( loadLongTermKey(<key) ) { // We already bonded with this peer previously // Encrypt the connection using stored Longterm Key - err = sd_ble_gap_encrypt(_conn_hdl, <keys.peer_enc.master_id, <keys.peer_enc.enc_info); - PRINT_STATUS(err); - - if ( err == NRF_SUCCESS ) + if ( secure->_encrypt(_conn_hdl, <key) ) { xSemaphoreTake(_pair_sem, portMAX_DELAY); @@ -276,21 +272,17 @@ bool BLEConnection::requestPairing(void) // delete bonds while we did not --> let's remove the obsolete keyfile and retry if ( !_paired ) { - bond_remove_key(_role, <keys.peer_id.id_addr_info); + bond_remove_key(_role, <key.peer_id.id_addr_info); // Re-try with a fresh session - err = sd_ble_gap_authenticate(_conn_hdl, &sec_param ); - PRINT_STATUS(err); - + secure->_authenticate(_conn_hdl); xSemaphoreTake(_pair_sem, portMAX_DELAY); } } }else { // start a fresh new authentication process - err = sd_ble_gap_authenticate(_conn_hdl, &sec_param ); - PRINT_STATUS(err); - + secure->_authenticate(_conn_hdl); xSemaphoreTake(_pair_sem, portMAX_DELAY); } diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.cpp b/libraries/Bluefruit52Lib/src/BLEPairing.cpp index d348c1be9..ed20438db 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.cpp +++ b/libraries/Bluefruit52Lib/src/BLEPairing.cpp @@ -195,6 +195,18 @@ void BLEPairing::setCompleteCallback(pair_complete_cb_t fp) _complete_cb = fp; } +bool BLEPairing::_authenticate(uint16_t conn_hdl) +{ + VERIFY_STATUS(sd_ble_gap_authenticate(conn_hdl, &_sec_param ), false); + return true; +} + +bool BLEPairing::_encrypt(uint16_t conn_hdl, bond_keys_t const* ltkey) +{ + VERIFY_STATUS(sd_ble_gap_encrypt(conn_hdl, <key->peer_enc.master_id, <key->peer_enc.enc_info), false); + return true; +} + //--------------------------------------------------------------------+ /* First-time Pairing * diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.h b/libraries/Bluefruit52Lib/src/BLEPairing.h index 27b2e8762..4701b5bdf 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.h +++ b/libraries/Bluefruit52Lib/src/BLEPairing.h @@ -42,7 +42,7 @@ class BLEPairing bool begin(void); - // Static Passkey + // Use static Passkey (Legacy SC) bool setPIN(const char* pin); // resolve address with IRK to see if it matches @@ -60,6 +60,9 @@ class BLEPairing ble_gap_sec_params_t getSecureParam(void) { return _sec_param; } void _eventHandler(ble_evt_t* evt); + bool _authenticate(uint16_t conn_hdl); + bool _encrypt(uint16_t conn_hdl, bond_keys_t const* ltkey); + private: ble_gap_sec_params_t _sec_param; From 2a53a5f810af05003f38214e29beaf813b679b65 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 17 Mar 2020 13:37:02 +0700 Subject: [PATCH 39/74] add Pairing setIOCaps() and setMITM() --- libraries/Bluefruit52Lib/src/BLEPairing.cpp | 96 +++++++++++++-------- libraries/Bluefruit52Lib/src/BLEPairing.h | 8 ++ 2 files changed, 69 insertions(+), 35 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.cpp b/libraries/Bluefruit52Lib/src/BLEPairing.cpp index ed20438db..56e1e672b 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.cpp +++ b/libraries/Bluefruit52Lib/src/BLEPairing.cpp @@ -27,7 +27,11 @@ //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM DECLARATION //--------------------------------------------------------------------+ -#define EDIV_INVALID 0xFFFF +#ifdef NRF_CRYPTOCELL + #define LESC_SUPPORTED 1 +#else + #define LESC_SUPPORTED 0 +#endif //------------- IMPLEMENTATION -------------// @@ -46,26 +50,24 @@ static void swap_endian(uint8_t data[], uint32_t nbytes) } } -BLEPairing::BLEPairing(void) +// default is Just Work +static const ble_gap_sec_params_t _sec_param_default = { - _sec_param = ((ble_gap_sec_params_t) - { - .bond = 1, - .mitm = 0, - .lesc = 0, - .keypress = 0, - .io_caps = BLE_GAP_IO_CAPS_NONE, - .oob = 0, - .min_key_size = 7, - .max_key_size = 16, - .kdist_own = { .enc = 1, .id = 1}, - .kdist_peer = { .enc = 1, .id = 1}, - }); - -#ifdef NRF_CRYPTOCELL -// _sec_param.lesc = 1; // enable LESC if CryptoCell is present -#endif + .bond = 1, + .mitm = 0, + .lesc = LESC_SUPPORTED, + .keypress = 0, + .io_caps = BLE_GAP_IO_CAPS_NONE, + .oob = 0, + .min_key_size = 7, + .max_key_size = 16, + .kdist_own = { .enc = 1, .id = 1}, + .kdist_peer = { .enc = 1, .id = 1} +}; +BLEPairing::BLEPairing(void) +{ + _sec_param = _sec_param_default; _passkey_cb = NULL; _complete_cb = NULL; } @@ -100,6 +102,39 @@ bool BLEPairing::begin(void) return true; } +void BLEPairing::setIOCaps(bool display, bool keyboard, bool yes_no) +{ + uint8_t io_caps = BLE_GAP_IO_CAPS_NONE; + + if (display) + { + if (keyboard) + { + io_caps = BLE_GAP_IO_CAPS_KEYBOARD_DISPLAY; + } + else if (yes_no) + { + io_caps = BLE_GAP_IO_CAPS_DISPLAY_YESNO; + }else + { + io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY; + } + }else + { + if (keyboard) io_caps = BLE_GAP_IO_CAPS_KEYBOARD_ONLY; + } + + _sec_param.io_caps = io_caps; + + // also set Man in the middle protection if we have some IO caps + if (io_caps != BLE_GAP_IO_CAPS_NONE) _sec_param.mitm = 1; +} + +void BLEPairing::setMITM(bool enabled) +{ + _sec_param.mitm = (enabled ? 1 : 0); +} + /* Resolvable Address = Hash (24 bit) | Random (24 bit) * in which * - Hash = AES(random) using IRK @@ -136,16 +171,13 @@ bool BLEPairing::resolveAddress(ble_gap_addr_t const * p_addr, ble_gap_irk_t con // Use Legacy SC static Passkey bool BLEPairing::setPIN(const char* pin) { - // back to open mode if (pin == NULL) { - _sec_param.bond = 1; - _sec_param.mitm = 0; - _sec_param.lesc = 0; // TODO NRF_CRYPTOCELL - _sec_param.io_caps = BLE_GAP_IO_CAPS_NONE; + // back to default mode + _sec_param = _sec_param_default; }else { - VERIFY ( strlen(pin) == BLE_GAP_PASSKEY_LEN ); + VERIFY(strlen(pin) == BLE_GAP_PASSKEY_LEN); // Static Passkey requires using // - Legacy SC @@ -158,7 +190,7 @@ bool BLEPairing::setPIN(const char* pin) ble_opt_t opt; opt.gap_opt.passkey.p_passkey = (const uint8_t*) pin; - VERIFY_STATUS( sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &opt), false); + VERIFY_STATUS(sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &opt), false); } return true; @@ -171,20 +203,14 @@ bool BLEPairing::setPasskeyCallback(pair_passkey_cb_t fp) if ( fp == NULL ) { - // TODO callback clear + // back to default mode + _sec_param = _sec_param_default; }else { _sec_param.bond = 1; _sec_param.mitm = 1; - - // TODO NRF_CRYPTOCELL -// _sec_param.lesc = 0; - _sec_param.lesc = 1; + _sec_param.lesc = LESC_SUPPORTED; _sec_param.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY; - - ble_opt_t opt; - opt.gap_opt.passkey.p_passkey = NULL; // generate Passkey randomly - VERIFY_STATUS( sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &opt), false); } return true; diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.h b/libraries/Bluefruit52Lib/src/BLEPairing.h index 4701b5bdf..c6ebdeeaf 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.h +++ b/libraries/Bluefruit52Lib/src/BLEPairing.h @@ -45,6 +45,12 @@ class BLEPairing // Use static Passkey (Legacy SC) bool setPIN(const char* pin); + // Set IO capacities + void setIOCaps(bool display, bool keyboard, bool yes_no); + + // Enable/Disable Man in the middle protection + void setMITM(bool enabled); + // resolve address with IRK to see if it matches bool resolveAddress(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * irk); @@ -52,6 +58,8 @@ class BLEPairing bool setPasskeyCallback(pair_passkey_cb_t fp); void setCompleteCallback(pair_complete_cb_t fp); + + /*------------------------------------------------------------------*/ /* INTERNAL USAGE ONLY * Although declare as public, it is meant to be invoked by internal From 61beff26b479965cf1cef5c3db0bc4b417dca2a0 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 17 Mar 2020 13:37:53 +0700 Subject: [PATCH 40/74] update pairing exmaple --- .../image_transfer/image_transfer.ino | 4 +- .../pairing_display/pairing_display.ino | 135 +++++++++++------- 2 files changed, 85 insertions(+), 54 deletions(-) diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/image_transfer/image_transfer.ino b/libraries/Bluefruit52Lib/examples/Peripheral/image_transfer/image_transfer.ino index 3ac9ee6a3..6b06ca019 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/image_transfer/image_transfer.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/image_transfer/image_transfer.ino @@ -55,14 +55,16 @@ // Default for others #define TFT_DC 10 #define TFT_CS 9 - #endif // 832 + #endif #if TFT_IN_USE == TFT_35_FEATHERWING #include "Adafruit_HX8357.h" Adafruit_HX8357 tft = Adafruit_HX8357(TFT_CS, TFT_DC); + #elif TFT_IN_USE == TFT_24_FEATHERWING #include Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); + #else #error "TFT display is not supported" #endif // TFT diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino index 18ce8fe0c..235389668 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino @@ -19,59 +19,68 @@ #include #include -/* This sketch demonstrates Pairing process using static Passkey aka PIN. +/* This sketch demonstrates Pairing process using dynamic Passkey. * This sketch is essentially the same as bleuart.ino except the BLE Uart * service requires Security Mode with Man-In-The-Middle protection i.e - * using 6 digits PIN for pairing. */ /* This sketch demonstrates the "Image Upload" feature of Bluefruit Mobile App. * Following TFT Display are supported - * - https://www.adafruit.com/product/3315 - * - https://www.adafruit.com/product/3651 - * - https://www.adafruit.com/product/4367 + * - TFT 3.5" : FeatherWing https://www.adafruit.com/product/3651 + * - TFT 2.4" : FeatherWing https://www.adafruit.com/product/3315 + * - TFT Gizmo : https://www.adafruit.com/product/4367 + * - Adafruit CLUE : https://www.adafruit.com/product/4500 */ -#define TFT_NONE 0 -#define TFT_35_FEATHERWING 1 -#define TFT_24_FEATHERWING 2 -#define TFT_GIZMO 3 +#define TFT_NO_DISPLAY 0 +#define TFT_GIZMO 1 // used with Circuit Playground Bluefruit +#define TFT_CLUE 2 // CLUE's on-board display +#define TFT_24_FEATHERWING 3 +#define TFT_35_FEATHERWING 4 -// [Configurable] Please select one of above supported Display to match your hardware setup -#define TFT_IN_USE TFT_NONE +#if defined(ARDUINO_NRF52840_CIRCUITPLAY) + // Circuit Playground Bluefruit use with TFT GIZMO + #define TFT_IN_USE TFT_GIZMO + #define DEVICE_NAME "CPLAY" -#if defined(ARDUINO_NRF52832_FEATHER) - // Feather nRF52832 - #define TFT_DC 11 - #define TFT_CS 31 + #include "Adafruit_ST7789.h" + Adafruit_ST7789 tft = Adafruit_ST7789(&SPI, 0, 1, -1); // CS = 0, DC = 1 + +#elif defined(ARDUINO_NRF52840_CLUE) + // CLUE use on-board TFT + #define TFT_IN_USE TFT_CLUE + #define DEVICE_NAME "CLUE" -#elif defined(ARDUINO_NRF52840_CIRCUITPLAY) - // Circuit Playground Bluefruit for use with TFT 1.5" GIZMO - #define TFT_DC 1 - #define TFT_CS 0 - #define TFT_BACKLIGHT A3 + #include "Adafruit_ST7789.h" + Adafruit_ST7789 tft = Adafruit_ST7789(&SPI1, PIN_TFT_CS, PIN_TFT_DC, PIN_TFT_RST); #else - // Default for others - #define TFT_DC 10 - #define TFT_CS 9 -#endif + // [Configurable] For other boards please select which external display to match your hardware setup + #define TFT_IN_USE TFT_24_FEATHERWING + #define DEVICE_NAME "Feather" + #if defined(ARDUINO_NRF52832_FEATHER) + // Feather nRF52832 pin map is different from others + #define TFT_DC 11 + #define TFT_CS 31 + #else + // Default for others + #define TFT_DC 10 + #define TFT_CS 9 + #endif -#if TFT_IN_USE == TFT_35_FEATHERWING - #include "Adafruit_HX8357.h" - Adafruit_HX8357 tft = Adafruit_HX8357(TFT_CS, TFT_DC); + #if TFT_IN_USE == TFT_35_FEATHERWING + #include "Adafruit_HX8357.h" + Adafruit_HX8357 tft = Adafruit_HX8357(TFT_CS, TFT_DC); -#elif TFT_IN_USE == TFT_24_FEATHERWING - #include - Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); + #elif TFT_IN_USE == TFT_24_FEATHERWING + #include + Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); + #endif // TFT -#elif TFT_IN_USE == TFT_GIZMO - #include "Adafruit_ST7789.h" - Adafruit_ST7789 tft = Adafruit_ST7789(&SPI, TFT_CS, TFT_DC, -1); +#endif // board variants -#endif #define COLOR_WHITE 0xFFFF #define COLOR_BLACK 0x0000 @@ -85,21 +94,36 @@ BLEUart bleuart; // uart over ble void setup() { Serial.begin(115200); - while(!Serial) delay(1); -#if TFT_IN_USE == TFT_GIZMO + Serial.println("Bluefruit52 Pairing Display Example"); + Serial.println("-----------------------------------\n"); + +#if TFT_IN_USE == TFT_CLUE + tft.init(240, 240); + tft.setRotation(1); + + // Screen refresh rate control (datasheet 9.2.18, FRCTRL2) + uint8_t rtna = 0x01; + tft.sendCommand(0xC6, &rtna, 1);; + + // turn back light on + uint8_t backlight = PIN_TFT_LITE; + pinMode(backlight, OUTPUT); + digitalWrite(backlight, HIGH); + +#elif TFT_IN_USE == TFT_GIZMO tft.init(240, 240); tft.setRotation(2); - pinMode(TFT_BACKLIGHT, OUTPUT); - digitalWrite(TFT_BACKLIGHT, HIGH); // Backlight on -#elif TFT_IN_USE != TFT_NONE - tft.begin(); + // turn back light on + uint8_t backlight = A3; + pinMode(backlight, OUTPUT); + digitalWrite(backlight, HIGH); -#endif +#elif TFT_IN_USE != TFT_NO_DISPLAY + tft.begin(); - Serial.println("Bluefruit52 BLEUART Example"); - Serial.println("---------------------------\n"); +#endif // TFT // Setup the BLE LED to be enabled on CONNECT // Note: This is actually the default behavior, but provided @@ -113,10 +137,15 @@ void setup() Bluefruit.begin(); Bluefruit.setTxPower(4); // Check bluefruit.h for supported values - Bluefruit.setName("Bluefruit52"); + Bluefruit.setName(DEVICE_NAME); + + // To use dynamic PassKey for pairing, we need to have + // - IO capacities at least DISPPLAY + // - Register callback to display/print dynamic passkey for central + Bluefruit.Pairing.setIOCaps(true, false, false); + Bluefruit.Pairing.setPasskeyCallback(pairing_passkey_callback); -// Serial.println("Setting pairing PIN to: " PAIRING_PIN); - Bluefruit.Pairing.setPasskeyCallback(pairing_display_callback); + // Set complete callback to print the pairing result Bluefruit.Pairing.setCompleteCallback(pairing_complete_callback); Bluefruit.Periph.setConnectCallback(connect_callback); @@ -136,7 +165,7 @@ void setup() Serial.println("Your phone should pop-up PIN input"); Serial.println("Once connected, enter character(s) that you wish to send"); -#if TFT_IN_USE != TFT_NONE +#if TFT_IN_USE != TFT_NO_DISPLAY tft.fillScreen(COLOR_BLACK); tft.setTextColor(COLOR_WHITE); tft.setTextSize(2); @@ -194,16 +223,16 @@ void loop() } } -void pairing_display_callback(uint16_t conn_handle, uint8_t const passkey[6]) +void pairing_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6]) { Serial.println("Enter this code on your phone to pair with Bluefruit:"); Serial.printf(" %.3s %.3s\n", passkey, passkey+3); -#if TFT_IN_USE != TFT_NONE +#if TFT_IN_USE != TFT_NO_DISPLAY tft.printf("Enter this code on your phone to pair with Bluefruit:\n\n"); tft.setTextColor(COLOR_YELLOW); tft.setTextSize(4); - tft.printf(" %.6s\n", passkey); + tft.printf(" %.3s %.3s\n", passkey, passkey+3); tft.setTextColor(COLOR_WHITE); tft.setTextSize(2); @@ -220,7 +249,7 @@ void pairing_complete_callback(uint16_t conn_handle, uint8_t auth_status) Serial.println("Failed"); } -#if TFT_IN_USE != TFT_NONE +#if TFT_IN_USE != TFT_NO_DISPLAY if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS) { tft.setTextColor(COLOR_GREEN); @@ -248,7 +277,7 @@ void connect_callback(uint16_t conn_handle) Serial.print("Connected to "); Serial.println(central_name); -#if TFT_IN_USE != TFT_NONE +#if TFT_IN_USE != TFT_NO_DISPLAY tft.fillScreen(COLOR_BLACK); tft.setTextSize(2); tft.setCursor(0, 0); @@ -269,7 +298,7 @@ void disconnect_callback(uint16_t conn_handle, uint8_t reason) Serial.println(); Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX); -#if TFT_IN_USE != TFT_NONE +#if TFT_IN_USE != TFT_NO_DISPLAY tft.println("Advertising ..."); #endif } From 44a98b6e9a9f123c55f690ba73542432358de31d Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 17 Mar 2020 17:01:49 +0700 Subject: [PATCH 41/74] enhance pairing to work with numberic comparison --- .../central_bleuart/central_bleuart.ino | 2 +- .../pairing_display/pairing_display.ino | 69 +++++++++++++++++-- libraries/Bluefruit52Lib/src/BLEPairing.cpp | 65 +++++++---------- libraries/Bluefruit52Lib/src/BLEPairing.h | 6 +- 4 files changed, 91 insertions(+), 51 deletions(-) diff --git a/libraries/Bluefruit52Lib/examples/Central/central_bleuart/central_bleuart.ino b/libraries/Bluefruit52Lib/examples/Central/central_bleuart/central_bleuart.ino index 992c9c69e..4085a9f5e 100644 --- a/libraries/Bluefruit52Lib/examples/Central/central_bleuart/central_bleuart.ino +++ b/libraries/Bluefruit52Lib/examples/Central/central_bleuart/central_bleuart.ino @@ -25,7 +25,7 @@ BLEClientUart clientUart; // bleuart client void setup() { Serial.begin(115200); - while ( !Serial ) delay(10); // for nrf52840 with native usb +// while ( !Serial ) delay(10); // for nrf52840 with native usb Serial.println("Bluefruit52 Central BLEUART Example"); Serial.println("-----------------------------------\n"); diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino index 235389668..999738494 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino @@ -22,6 +22,13 @@ /* This sketch demonstrates Pairing process using dynamic Passkey. * This sketch is essentially the same as bleuart.ino except the BLE Uart * service requires Security Mode with Man-In-The-Middle protection i.e + * + * BLE Pairing procedure is complicated, it is advisable for users to go through + * these articles to get familiar with the procedure and terminology + * - https://www.bluetooth.com/blog/bluetooth-pairing-part-1-pairing-feature-exchange/ + * - https://www.bluetooth.com/blog/bluetooth-pairing-part-2-key-generation-methods/ + * - https://www.bluetooth.com/blog/bluetooth-pairing-passkey-entry/ + * - https://www.bluetooth.com/blog/bluetooth-pairing-part-4/ */ /* This sketch demonstrates the "Image Upload" feature of Bluefruit Mobile App. @@ -125,6 +132,9 @@ void setup() #endif // TFT + pinMode(PIN_BUTTON1, INPUT_PULLUP); + pinMode(PIN_BUTTON2, INPUT_PULLUP); + // Setup the BLE LED to be enabled on CONNECT // Note: This is actually the default behavior, but provided // here in case you want to control this LED manually via PIN 19 @@ -142,7 +152,9 @@ void setup() // To use dynamic PassKey for pairing, we need to have // - IO capacities at least DISPPLAY // - Register callback to display/print dynamic passkey for central - Bluefruit.Pairing.setIOCaps(true, false, false); + // For complete mapping of the IO Capabilities to Key Generation Method, check out this article + // https://www.bluetooth.com/blog/bluetooth-pairing-part-2-key-generation-methods/ + Bluefruit.Pairing.setIOCaps(true, true, false); // display = true, yes/no = true, keyboard = false Bluefruit.Pairing.setPasskeyCallback(pairing_passkey_callback); // Set complete callback to print the pairing result @@ -223,20 +235,67 @@ void loop() } } -void pairing_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6]) +// callback invoked when pairing passkey is generated +// - passkey: 6 keys (without null terminator) for displaying +// - match_request: true when authentication method is Numberic Comparison. +// Then this callback's return value is used to accept (true) or +// reject (false) the pairing process. Otherwise, return value has no effect +bool pairing_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6], bool match_request) { - Serial.println("Enter this code on your phone to pair with Bluefruit:"); + Serial.println("Pairing Passkey"); Serial.printf(" %.3s %.3s\n", passkey, passkey+3); #if TFT_IN_USE != TFT_NO_DISPLAY - tft.printf("Enter this code on your phone to pair with Bluefruit:\n\n"); + tft.fillScreen(COLOR_BLACK); + tft.println("Pairing Passkey\n"); tft.setTextColor(COLOR_YELLOW); tft.setTextSize(4); - tft.printf(" %.3s %.3s\n", passkey, passkey+3); + tft.printf(" %.3s %.3s\n", passkey, passkey+3); tft.setTextColor(COLOR_WHITE); tft.setTextSize(2); #endif + + + if (match_request) + { + Serial.println("Do you want to pair"); + Serial.println("Press Button A to accept, Button B to reject"); + + #if TFT_IN_USE != TFT_NO_DISPLAY + tft.println("\nDo you accept ?\n\n"); + + tft.setTextSize(3); + tft.setTextColor(COLOR_GREEN); + tft.print("<< Yes"); + tft.setTextColor(COLOR_RED); + tft.println(" No >>"); + + tft.setTextColor(COLOR_WHITE); + tft.setTextSize(2); + #endif + + // wait until either button is pressed + while( digitalRead(PIN_BUTTON1) && digitalRead(PIN_BUTTON2) ) { } + + // wait until either button is pressed + uint32_t start_time = millis(); + while( digitalRead(PIN_BUTTON1) && digitalRead(PIN_BUTTON2) ) + { + // 30 seconds timeout + if ( millis() > start_time + 30000 ) break; + } + + // A = accept + if ( 0 == digitalRead(PIN_BUTTON1) ) return true; + + // B = reject + if ( 0 == digitalRead(PIN_BUTTON2) ) return false; + + return false; + } + + return true; } void pairing_complete_callback(uint16_t conn_handle, uint8_t auth_status) diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.cpp b/libraries/Bluefruit52Lib/src/BLEPairing.cpp index 56e1e672b..3ce191bc9 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.cpp +++ b/libraries/Bluefruit52Lib/src/BLEPairing.cpp @@ -102,7 +102,7 @@ bool BLEPairing::begin(void) return true; } -void BLEPairing::setIOCaps(bool display, bool keyboard, bool yes_no) +void BLEPairing::setIOCaps(bool display, bool yes_no, bool keyboard) { uint8_t io_caps = BLE_GAP_IO_CAPS_NONE; @@ -125,9 +125,6 @@ void BLEPairing::setIOCaps(bool display, bool keyboard, bool yes_no) } _sec_param.io_caps = io_caps; - - // also set Man in the middle protection if we have some IO caps - if (io_caps != BLE_GAP_IO_CAPS_NONE) _sec_param.mitm = 1; } void BLEPairing::setMITM(bool enabled) @@ -171,27 +168,19 @@ bool BLEPairing::resolveAddress(ble_gap_addr_t const * p_addr, ble_gap_irk_t con // Use Legacy SC static Passkey bool BLEPairing::setPIN(const char* pin) { - if (pin == NULL) - { - // back to default mode - _sec_param = _sec_param_default; - }else - { - VERIFY(strlen(pin) == BLE_GAP_PASSKEY_LEN); - - // Static Passkey requires using - // - Legacy SC - // - IO cap: Display - // - MITM is on - _sec_param.bond = 1; - _sec_param.mitm = 1; - _sec_param.lesc = 0; - _sec_param.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY; - - ble_opt_t opt; - opt.gap_opt.passkey.p_passkey = (const uint8_t*) pin; - VERIFY_STATUS(sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &opt), false); - } + VERIFY(pin && strlen(pin) == BLE_GAP_PASSKEY_LEN); + + // Static Passkey requires using + // - Legacy SC + // - IO cap: Display + // - MITM is on + _sec_param.mitm = 1; + _sec_param.lesc = 0; + _sec_param.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY; + + ble_opt_t opt; + opt.gap_opt.passkey.p_passkey = (const uint8_t*) pin; + VERIFY_STATUS(sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &opt), false); return true; } @@ -201,17 +190,8 @@ bool BLEPairing::setPasskeyCallback(pair_passkey_cb_t fp) { _passkey_cb = fp; - if ( fp == NULL ) - { - // back to default mode - _sec_param = _sec_param_default; - }else - { - _sec_param.bond = 1; - _sec_param.mitm = 1; - _sec_param.lesc = LESC_SUPPORTED; - _sec_param.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY; - } + // mitm is required to trigger passkey generation + _sec_param.mitm = 1; return true; } @@ -304,12 +284,15 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) LOG_LV2("PAIR", "Passkey = %.6s, match request = %d", passkey_display->passkey, passkey_display->match_request); // Invoke display callback - if ( _passkey_cb ) ada_callback(passkey_display->passkey, 6, _passkey_cb, conn_hdl, passkey_display->passkey); - - if (passkey_display->match_request) + if ( _passkey_cb ) { - // Match request require to report the match - // sd_ble_gap_auth_key_reply(); + bool matched = _passkey_cb(conn_hdl, passkey_display->passkey, passkey_display->match_request); + + if (passkey_display->match_request) + { + // Match request require to report the match (numberic comparison) + sd_ble_gap_auth_key_reply(conn_hdl, matched ? BLE_GAP_AUTH_KEY_TYPE_PASSKEY : BLE_GAP_AUTH_KEY_TYPE_NONE, NULL); + } } } break; diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.h b/libraries/Bluefruit52Lib/src/BLEPairing.h index c6ebdeeaf..6a249f069 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.h +++ b/libraries/Bluefruit52Lib/src/BLEPairing.h @@ -35,7 +35,7 @@ class BLEPairing { public: - typedef void (*pair_passkey_cb_t ) (uint16_t conn_hdl, uint8_t const passkey[6]); + typedef bool (*pair_passkey_cb_t ) (uint16_t conn_hdl, uint8_t const passkey[6], bool match_request); typedef void (*pair_complete_cb_t) (uint16_t conn_hdl, uint8_t auth_status); BLEPairing(void); @@ -46,7 +46,7 @@ class BLEPairing bool setPIN(const char* pin); // Set IO capacities - void setIOCaps(bool display, bool keyboard, bool yes_no); + void setIOCaps(bool display, bool yes_no, bool keyboard); // Enable/Disable Man in the middle protection void setMITM(bool enabled); @@ -58,8 +58,6 @@ class BLEPairing bool setPasskeyCallback(pair_passkey_cb_t fp); void setCompleteCallback(pair_complete_cb_t fp); - - /*------------------------------------------------------------------*/ /* INTERNAL USAGE ONLY * Although declare as public, it is meant to be invoked by internal From a5fea5644b30d41c0ddde9016c8c64bd9c2ee3b7 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 17 Mar 2020 23:42:26 +0700 Subject: [PATCH 42/74] clean up --- libraries/Bluefruit52Lib/src/BLEPeriph.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/BLEPeriph.cpp b/libraries/Bluefruit52Lib/src/BLEPeriph.cpp index fab8908db..c6d5209ed 100644 --- a/libraries/Bluefruit52Lib/src/BLEPeriph.cpp +++ b/libraries/Bluefruit52Lib/src/BLEPeriph.cpp @@ -126,6 +126,7 @@ void BLEPeriph::setDisconnectCallback( ble_disconnect_callback_t fp ) void BLEPeriph::_eventHandler(ble_evt_t* evt) { uint16_t const conn_hdl = evt->evt.common_evt.conn_handle; + BLEConnection* conn = Bluefruit.Connection(conn_hdl); switch ( evt->header.evt_id ) { @@ -133,14 +134,11 @@ void BLEPeriph::_eventHandler(ble_evt_t* evt) { ble_gap_evt_connected_t* para = &evt->evt.gap_evt.params.connected; - if (para->role == BLE_GAP_ROLE_PERIPH) + // Connection interval set by Central is out of preferred range + // Try to negotiate with Central using our preferred values + if ( !is_within(_ppcp.min_conn_interval, para->conn_params.min_conn_interval, _ppcp.max_conn_interval) ) { - // Connection interval set by Central is out of preferred range - // Try to negotiate with Central using our preferred values - if ( !is_within(_ppcp.min_conn_interval, para->conn_params.min_conn_interval, _ppcp.max_conn_interval) ) - { - VERIFY_STATUS( sd_ble_gap_conn_param_update(conn_hdl, &_ppcp), ); - } + VERIFY_STATUS( sd_ble_gap_conn_param_update(conn_hdl, &_ppcp), ); } } break; From ddded486426d9131aa59751fec2008ac1751a36f Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 17 Mar 2020 23:44:09 +0700 Subject: [PATCH 43/74] fix central reconnection with LESC --- libraries/Bluefruit52Lib/src/BLEPairing.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.cpp b/libraries/Bluefruit52Lib/src/BLEPairing.cpp index 3ce191bc9..83e9bfdfc 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.cpp +++ b/libraries/Bluefruit52Lib/src/BLEPairing.cpp @@ -209,7 +209,9 @@ bool BLEPairing::_authenticate(uint16_t conn_hdl) bool BLEPairing::_encrypt(uint16_t conn_hdl, bond_keys_t const* ltkey) { - VERIFY_STATUS(sd_ble_gap_encrypt(conn_hdl, <key->peer_enc.master_id, <key->peer_enc.enc_info), false); + // LESC use own key, Legacy use peer key + ble_gap_enc_key_t const* enc_key = ltkey->own_enc.enc_info.lesc ? <key->own_enc : <key->peer_enc; + VERIFY_STATUS(sd_ble_gap_encrypt(conn_hdl, &enc_key->master_id, &enc_key->enc_info), false); return true; } @@ -347,9 +349,6 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) // Pairing succeeded --> save encryption keys ( Bonding ) if (BLE_GAP_SEC_STATUS_SUCCESS == status->auth_status) { - LOG_LV2("PAIR", "Ediv = 0x%02X", _bond_keys.own_enc.master_id.ediv); - LOG_LV2_BUFFER("Rand", _bond_keys.own_enc.master_id.rand, 8); - conn->saveLongTermKey(&_bond_keys); } From 35262982c45c6da64d65c8511d9568be5c785bfd Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 18 Mar 2020 00:34:29 +0700 Subject: [PATCH 44/74] central auto use stored keys if bonded previously --- libraries/Bluefruit52Lib/src/BLECentral.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libraries/Bluefruit52Lib/src/BLECentral.cpp b/libraries/Bluefruit52Lib/src/BLECentral.cpp index 467e23255..834008510 100644 --- a/libraries/Bluefruit52Lib/src/BLECentral.cpp +++ b/libraries/Bluefruit52Lib/src/BLECentral.cpp @@ -133,12 +133,22 @@ void BLECentral::_eventHandler(ble_evt_t* evt) { // conn handle has fixed offset regardless of event type const uint16_t conn_hdl = evt->evt.common_evt.conn_handle; + BLEConnection* conn = Bluefruit.Connection(conn_hdl); /* PrPh handle connection is already filtered. Only handle Central events or * connection handle is BLE_CONN_HANDLE_INVALID (e.g BLE_GAP_EVT_ADV_REPORT) */ switch ( evt->header.evt_id ) { case BLE_GAP_EVT_CONNECTED: + { + // Try to secure connection if we bonded previously + static bond_keys_t ltkey; + if ( conn->loadLongTermKey(<key) ) + { + BLEPairing* secure = &Bluefruit.Pairing; + secure->_encrypt(conn_hdl, <key); + } + } break; case BLE_GAP_EVT_DISCONNECTED: From 1210b3e7c04f24a111d249222d01bdd3151cd94a Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 18 Mar 2020 10:14:57 +0700 Subject: [PATCH 45/74] BLEConnection add _bonded, rename _paired to _secured --- .../Bluefruit52Lib/src/BLEConnection.cpp | 65 ++++++++++--------- libraries/Bluefruit52Lib/src/BLEConnection.h | 4 +- 2 files changed, 39 insertions(+), 30 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.cpp b/libraries/Bluefruit52Lib/src/BLEConnection.cpp index 59d473354..662981b65 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.cpp +++ b/libraries/Bluefruit52Lib/src/BLEConnection.cpp @@ -55,7 +55,7 @@ BLEConnection::BLEConnection(uint16_t conn_hdl, ble_gap_evt_connected_t const* e _hvn_sem = xSemaphoreCreateCounting(hvn_qsize, hvn_qsize); _wrcmd_sem = xSemaphoreCreateCounting(wrcmd_qsize, wrcmd_qsize); - _paired = false; + _secured = false; _hvc_sem = NULL; _hvc_received = false; _pair_sem = NULL; @@ -85,7 +85,12 @@ bool BLEConnection::connected(void) bool BLEConnection::paired (void) { - return _paired; + return _secured; +} + +bool BLEConnection::bonded(void) +{ + return _bonded; } uint8_t BLEConnection::getRole (void) @@ -236,13 +241,15 @@ bool BLEConnection::saveLongTermKey(bond_keys_t const* ltkey) { bond_save_keys(_role, _conn_hdl, ltkey); _bond_id_addr = ltkey->peer_id.id_addr_info; - _paired = true; // paired with new device + _secured = true; // paired with new device + _bonded = true; return true; } bool BLEConnection::loadLongTermKey(bond_keys_t* ltkey) { - VERIFY( bond_load_keys(_role, &_peer_addr, ltkey) ); + _bonded = bond_load_keys(_role, &_peer_addr, ltkey); + VERIFY(_bonded); _bond_id_addr = ltkey->peer_id.id_addr_info; return true; } @@ -250,7 +257,7 @@ bool BLEConnection::loadLongTermKey(bond_keys_t* ltkey) bool BLEConnection::requestPairing(void) { // skip if already paired - if ( _paired ) return true; + if ( _secured ) return true; BLEPairing* secure = &Bluefruit.Pairing; @@ -258,28 +265,28 @@ bool BLEConnection::requestPairing(void) _pair_sem = xSemaphoreCreateBinary(); VERIFY(_pair_sem); - bond_keys_t ltkey; - - if ( loadLongTermKey(<key) ) - { - // We already bonded with this peer previously - // Encrypt the connection using stored Longterm Key - if ( secure->_encrypt(_conn_hdl, <key) ) - { - xSemaphoreTake(_pair_sem, portMAX_DELAY); - - // Failed to pair using stored key, this happens when peer - // delete bonds while we did not --> let's remove the obsolete keyfile and retry - if ( !_paired ) - { - bond_remove_key(_role, <key.peer_id.id_addr_info); - - // Re-try with a fresh session - secure->_authenticate(_conn_hdl); - xSemaphoreTake(_pair_sem, portMAX_DELAY); - } - } - }else +// bond_keys_t ltkey; +// +// if ( loadLongTermKey(<key) ) // central only +// { +// // We already bonded with this peer previously +// // Encrypt the connection using stored Longterm Key +// if ( secure->_encrypt(_conn_hdl, <key) ) +// { +// xSemaphoreTake(_pair_sem, portMAX_DELAY); +// +// // Failed to pair using stored key, this happens when peer +// // delete bonds while we did not --> let's remove the obsolete keyfile and retry +// if ( !_paired ) +// { +// bond_remove_key(_role, <key.peer_id.id_addr_info); +// +// // Re-try with a fresh session +// secure->_authenticate(_conn_hdl); +// xSemaphoreTake(_pair_sem, portMAX_DELAY); +// } +// } +// }else { // start a fresh new authentication process secure->_authenticate(_conn_hdl); @@ -289,7 +296,7 @@ bool BLEConnection::requestPairing(void) vSemaphoreDelete(_pair_sem); _pair_sem = NULL; - return _paired; + return _secured; } bool BLEConnection::waitForIndicateConfirm(void) @@ -324,7 +331,7 @@ void BLEConnection::_eventHandler(ble_evt_t* evt) // Connection is secured (paired) if encryption level > 1 if ( !( conn_sec->sec_mode.sm == 1 && conn_sec->sec_mode.lv == 1) ) { - _paired = true; + _secured = true; // Try to restore CCCD with bonded peer, if it doesn't exist (newly bonded), initialize it if ( !loadCccd() ) sd_ble_gatts_sys_attr_set(_conn_hdl, NULL, 0, 0); diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.h b/libraries/Bluefruit52Lib/src/BLEConnection.h index 80b99b5c5..0d3f0c42c 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.h +++ b/libraries/Bluefruit52Lib/src/BLEConnection.h @@ -54,7 +54,8 @@ class BLEConnection uint16_t _ediv; bool _connected; - bool _paired; + bool _secured; + bool _bonded; // have LTK stored in InternalFS bool _hvc_received; ble_gap_addr_t _peer_addr; // resolvable connect address @@ -74,6 +75,7 @@ class BLEConnection uint16_t handle(void); bool connected(void); bool paired(void); + bool bonded(void); uint8_t getRole(void); uint16_t getMtu (void); From d0e59469741ecc8f89a4bf3db3bb6cca43d80128 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 18 Mar 2020 10:55:05 +0700 Subject: [PATCH 46/74] rename save/load BondKey --- libraries/Bluefruit52Lib/src/BLEConnection.cpp | 12 ++++++++---- libraries/Bluefruit52Lib/src/BLEConnection.h | 8 +++++--- libraries/Bluefruit52Lib/src/BLEPairing.cpp | 14 ++++++++------ libraries/Bluefruit52Lib/src/services/BLEDfu.cpp | 2 +- 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.cpp b/libraries/Bluefruit52Lib/src/BLEConnection.cpp index 662981b65..0e70a6394 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.cpp +++ b/libraries/Bluefruit52Lib/src/BLEConnection.cpp @@ -93,6 +93,11 @@ bool BLEConnection::bonded(void) return _bonded; } +bool BLEConnection::secured(void) +{ + return _secured; +} + uint8_t BLEConnection::getRole (void) { return _role; @@ -237,16 +242,15 @@ bool BLEConnection::loadCccd(void) return bond_load_cccd(_role, _conn_hdl, &_bond_id_addr); } -bool BLEConnection::saveLongTermKey(bond_keys_t const* ltkey) +bool BLEConnection::saveBondKey(bond_keys_t const* ltkey) { bond_save_keys(_role, _conn_hdl, ltkey); _bond_id_addr = ltkey->peer_id.id_addr_info; - _secured = true; // paired with new device _bonded = true; return true; } -bool BLEConnection::loadLongTermKey(bond_keys_t* ltkey) +bool BLEConnection::loadBondKey(bond_keys_t* ltkey) { _bonded = bond_load_keys(_role, &_peer_addr, ltkey); VERIFY(_bonded); @@ -267,7 +271,7 @@ bool BLEConnection::requestPairing(void) // bond_keys_t ltkey; // -// if ( loadLongTermKey(<key) ) // central only +// if ( loadBondKey(<key) ) // central only // { // // We already bonded with this peer previously // // Encrypt the connection using stored Longterm Key diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.h b/libraries/Bluefruit52Lib/src/BLEConnection.h index 0d3f0c42c..7a0f402f3 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.h +++ b/libraries/Bluefruit52Lib/src/BLEConnection.h @@ -74,8 +74,9 @@ class BLEConnection uint16_t handle(void); bool connected(void); - bool paired(void); + bool paired(void); // todo removed bool bonded(void); + bool secured(void); uint8_t getRole(void); uint16_t getMtu (void); @@ -105,8 +106,9 @@ class BLEConnection bool getWriteCmdPacket(void); bool waitForIndicateConfirm(void); - bool saveLongTermKey(bond_keys_t const* ltkey); - bool loadLongTermKey(bond_keys_t* ltkey); + bool saveBondKey(bond_keys_t const* ltkey); + bool loadBondKey(bond_keys_t* ltkey); + bool removeBondKey(void); bool saveCccd(void); bool loadCccd(void); diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.cpp b/libraries/Bluefruit52Lib/src/BLEPairing.cpp index 83e9bfdfc..43f48d392 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.cpp +++ b/libraries/Bluefruit52Lib/src/BLEPairing.cpp @@ -349,7 +349,7 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) // Pairing succeeded --> save encryption keys ( Bonding ) if (BLE_GAP_SEC_STATUS_SUCCESS == status->auth_status) { - conn->saveLongTermKey(&_bond_keys); + conn->saveBondKey(&_bond_keys); } // Invoke callback @@ -364,17 +364,19 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) // - Else return NULL --> Initiate key exchange ble_gap_evt_sec_info_request_t* sec_info = (ble_gap_evt_sec_info_request_t*) &evt->evt.gap_evt.params.sec_info_request; - LOG_LV2("PAIR", "Addr ID = %d, Addr Type = 0x%02X", sec_info->peer_addr.addr_id_peer, sec_info->peer_addr.addr_type); - LOG_LV2_BUFFER("Address", sec_info->peer_addr.addr, 6); + LOG_LV2("PAIR", "Address: ID = %d, Type = 0x%02X, %02X:%02X:%02X:%02X:%02X:%02X", + sec_info->peer_addr.addr_id_peer, sec_info->peer_addr.addr_type, + sec_info->peer_addr.addr[0], sec_info->peer_addr.addr[1], sec_info->peer_addr.addr[2], + sec_info->peer_addr.addr[3], sec_info->peer_addr.addr[4], sec_info->peer_addr.addr[5]); bond_keys_t bkeys; - if ( conn->loadLongTermKey(&bkeys) ) + if ( conn->loadBondKey(&bkeys) ) { - sd_ble_gap_sec_info_reply(conn_hdl, &bkeys.own_enc.enc_info, &bkeys.peer_id.id_info, NULL); + VERIFY_STATUS(sd_ble_gap_sec_info_reply(conn_hdl, &bkeys.own_enc.enc_info, &bkeys.peer_id.id_info, NULL), ); } else { - sd_ble_gap_sec_info_reply(conn_hdl, NULL, NULL, NULL); + VERIFY_STATUS(sd_ble_gap_sec_info_reply(conn_hdl, NULL, NULL, NULL), ); } } break; diff --git a/libraries/Bluefruit52Lib/src/services/BLEDfu.cpp b/libraries/Bluefruit52Lib/src/services/BLEDfu.cpp index 675145be7..70abcd28d 100644 --- a/libraries/Bluefruit52Lib/src/services/BLEDfu.cpp +++ b/libraries/Bluefruit52Lib/src/services/BLEDfu.cpp @@ -140,7 +140,7 @@ static void bledfu_control_wr_authorize_cb(uint16_t conn_hdl, BLECharacteristic* if ( conn->paired() ) { bond_keys_t bkeys; - if ( conn->loadLongTermKey(&bkeys) ) + if ( conn->loadBondKey(&bkeys) ) { peer_data->addr = bkeys.peer_id.id_addr_info; peer_data->irk = bkeys.peer_id.id_info; From 7cc13075176527b5913f810b9c702f8cd027082f Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 18 Mar 2020 11:00:06 +0700 Subject: [PATCH 47/74] central auto removes failed bond keys --- libraries/Bluefruit52Lib/src/BLECentral.cpp | 13 +++++++++++-- libraries/Bluefruit52Lib/src/BLEConnection.cpp | 7 +++++++ libraries/Bluefruit52Lib/src/utility/bonding.cpp | 2 ++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/BLECentral.cpp b/libraries/Bluefruit52Lib/src/BLECentral.cpp index 834008510..d8210d66b 100644 --- a/libraries/Bluefruit52Lib/src/BLECentral.cpp +++ b/libraries/Bluefruit52Lib/src/BLECentral.cpp @@ -142,8 +142,8 @@ void BLECentral::_eventHandler(ble_evt_t* evt) case BLE_GAP_EVT_CONNECTED: { // Try to secure connection if we bonded previously - static bond_keys_t ltkey; - if ( conn->loadLongTermKey(<key) ) + bond_keys_t ltkey; + if ( conn->loadBondKey(<key) ) { BLEPairing* secure = &Bluefruit.Pairing; secure->_encrypt(conn_hdl, <key); @@ -154,6 +154,15 @@ void BLECentral::_eventHandler(ble_evt_t* evt) case BLE_GAP_EVT_DISCONNECTED: break; + case BLE_GAP_EVT_CONN_SEC_UPDATE: + if ( conn->bonded() && !conn->secured() ) + { + // Bonded but failed to secure connection + // Peer must have removed LTKey, we should remove ours as well + conn->removeBondKey(); + } + break; + case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: { // Peripheral request to change connection parameter diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.cpp b/libraries/Bluefruit52Lib/src/BLEConnection.cpp index 0e70a6394..f3f5702d5 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.cpp +++ b/libraries/Bluefruit52Lib/src/BLEConnection.cpp @@ -258,6 +258,13 @@ bool BLEConnection::loadBondKey(bond_keys_t* ltkey) return true; } +bool BLEConnection::removeBondKey(void) +{ + VERIFY(_bonded); + bond_remove_key(_role, &_bond_id_addr); + return true; +} + bool BLEConnection::requestPairing(void) { // skip if already paired diff --git a/libraries/Bluefruit52Lib/src/utility/bonding.cpp b/libraries/Bluefruit52Lib/src/utility/bonding.cpp index 387bec16f..7f53b319a 100644 --- a/libraries/Bluefruit52Lib/src/utility/bonding.cpp +++ b/libraries/Bluefruit52Lib/src/utility/bonding.cpp @@ -356,4 +356,6 @@ void bond_remove_key(uint8_t role, ble_gap_addr_t const* id_addr) get_fname(filename, role, id_addr->addr); InternalFS.remove(filename); + + BOND_LOG("Removed keys from file %s", filename); } From f0440b55ea2c365e24b4b12ce0d3e977334276c1 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 18 Mar 2020 11:25:52 +0700 Subject: [PATCH 48/74] Pairing added secured callback, requestPairing() is non-blocking now. --- .../Bluefruit52Lib/src/BLEConnection.cpp | 46 +------------------ libraries/Bluefruit52Lib/src/BLEPairing.cpp | 18 ++++++++ libraries/Bluefruit52Lib/src/BLEPairing.h | 4 +- 3 files changed, 23 insertions(+), 45 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.cpp b/libraries/Bluefruit52Lib/src/BLEConnection.cpp index f3f5702d5..6daad956e 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.cpp +++ b/libraries/Bluefruit52Lib/src/BLEConnection.cpp @@ -56,9 +56,9 @@ BLEConnection::BLEConnection(uint16_t conn_hdl, ble_gap_evt_connected_t const* e _wrcmd_sem = xSemaphoreCreateCounting(wrcmd_qsize, wrcmd_qsize); _secured = false; + _bonded = false; _hvc_sem = NULL; _hvc_received = false; - _pair_sem = NULL; _ediv = 0xFFFF; } @@ -70,7 +70,6 @@ BLEConnection::~BLEConnection() //------------- on-the-fly data must be freed -------------// if (_hvc_sem ) vSemaphoreDelete(_hvc_sem ); - if (_pair_sem ) vSemaphoreDelete(_pair_sem); } uint16_t BLEConnection::handle (void) @@ -270,44 +269,7 @@ bool BLEConnection::requestPairing(void) // skip if already paired if ( _secured ) return true; - BLEPairing* secure = &Bluefruit.Pairing; - - // on-the-fly semaphore - _pair_sem = xSemaphoreCreateBinary(); - VERIFY(_pair_sem); - -// bond_keys_t ltkey; -// -// if ( loadBondKey(<key) ) // central only -// { -// // We already bonded with this peer previously -// // Encrypt the connection using stored Longterm Key -// if ( secure->_encrypt(_conn_hdl, <key) ) -// { -// xSemaphoreTake(_pair_sem, portMAX_DELAY); -// -// // Failed to pair using stored key, this happens when peer -// // delete bonds while we did not --> let's remove the obsolete keyfile and retry -// if ( !_paired ) -// { -// bond_remove_key(_role, <key.peer_id.id_addr_info); -// -// // Re-try with a fresh session -// secure->_authenticate(_conn_hdl); -// xSemaphoreTake(_pair_sem, portMAX_DELAY); -// } -// } -// }else - { - // start a fresh new authentication process - secure->_authenticate(_conn_hdl); - xSemaphoreTake(_pair_sem, portMAX_DELAY); - } - - vSemaphoreDelete(_pair_sem); - _pair_sem = NULL; - - return _secured; + return Bluefruit.Pairing._authenticate(_conn_hdl); } bool BLEConnection::waitForIndicateConfirm(void) @@ -335,9 +297,7 @@ void BLEConnection::_eventHandler(ble_evt_t* evt) case BLE_GAP_EVT_CONN_SEC_UPDATE: { - // Connection is secured, we have paired/bonded const ble_gap_conn_sec_t* conn_sec = &evt->evt.gap_evt.params.conn_sec_update.conn_sec; - LOG_LV2("PAIR", "Security Mode = %d, Level = %d", conn_sec->sec_mode.sm, conn_sec->sec_mode.lv); // Connection is secured (paired) if encryption level > 1 if ( !( conn_sec->sec_mode.sm == 1 && conn_sec->sec_mode.lv == 1) ) @@ -347,8 +307,6 @@ void BLEConnection::_eventHandler(ble_evt_t* evt) // Try to restore CCCD with bonded peer, if it doesn't exist (newly bonded), initialize it if ( !loadCccd() ) sd_ble_gatts_sys_attr_set(_conn_hdl, NULL, 0, 0); } - - if (_pair_sem) xSemaphoreGive(_pair_sem); } break; diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.cpp b/libraries/Bluefruit52Lib/src/BLEPairing.cpp index 43f48d392..be7711c96 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.cpp +++ b/libraries/Bluefruit52Lib/src/BLEPairing.cpp @@ -70,6 +70,7 @@ BLEPairing::BLEPairing(void) _sec_param = _sec_param_default; _passkey_cb = NULL; _complete_cb = NULL; + _secured_cb = NULL; } bool BLEPairing::begin(void) @@ -201,6 +202,11 @@ void BLEPairing::setCompleteCallback(pair_complete_cb_t fp) _complete_cb = fp; } +void BLEPairing::setSecuredCallback(pair_secured_cb_t fp) +{ + _secured_cb = fp; +} + bool BLEPairing::_authenticate(uint16_t conn_hdl) { VERIFY_STATUS(sd_ble_gap_authenticate(conn_hdl, &_sec_param ), false); @@ -381,6 +387,18 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) } break; + case BLE_GAP_EVT_CONN_SEC_UPDATE: + { + const ble_gap_conn_sec_t* conn_sec = &evt->evt.gap_evt.params.conn_sec_update.conn_sec; + LOG_LV2("PAIR", "Security Mode = %d, Level = %d", conn_sec->sec_mode.sm, conn_sec->sec_mode.lv); + + if ( conn->secured() && _secured_cb ) + { + ada_callback(NULL, 0, _secured_cb, conn_hdl, conn_sec->sec_mode.sm, conn_sec->sec_mode.lv); + } + } + break; + default: break; } } diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.h b/libraries/Bluefruit52Lib/src/BLEPairing.h index 6a249f069..9c17f8b9d 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.h +++ b/libraries/Bluefruit52Lib/src/BLEPairing.h @@ -37,6 +37,7 @@ class BLEPairing public: typedef bool (*pair_passkey_cb_t ) (uint16_t conn_hdl, uint8_t const passkey[6], bool match_request); typedef void (*pair_complete_cb_t) (uint16_t conn_hdl, uint8_t auth_status); + typedef void (*pair_secured_cb_t) (uint16_t conn_hdl, uint8_t sec_mode, uint8_t level); BLEPairing(void); @@ -57,13 +58,13 @@ class BLEPairing //------------- Callbacks -------------// bool setPasskeyCallback(pair_passkey_cb_t fp); void setCompleteCallback(pair_complete_cb_t fp); + void setSecuredCallback(pair_secured_cb_t fp); /*------------------------------------------------------------------*/ /* INTERNAL USAGE ONLY * Although declare as public, it is meant to be invoked by internal * code. User should not call these directly *------------------------------------------------------------------*/ - ble_gap_sec_params_t getSecureParam(void) { return _sec_param; } void _eventHandler(ble_evt_t* evt); bool _authenticate(uint16_t conn_hdl); @@ -81,6 +82,7 @@ class BLEPairing pair_passkey_cb_t _passkey_cb; pair_complete_cb_t _complete_cb; + pair_secured_cb_t _secured_cb; }; #endif /* BLEPAIRING_H_ */ From f35ca052f5baf31efbe582095a5fa4072ffad493 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 18 Mar 2020 14:22:36 +0700 Subject: [PATCH 49/74] added secured callback --- .../Bluefruit52Lib/src/BLEConnection.cpp | 20 +++++--- libraries/Bluefruit52Lib/src/BLEConnection.h | 6 ++- libraries/Bluefruit52Lib/src/BLEPairing.cpp | 49 ++++++++++--------- libraries/Bluefruit52Lib/src/BLEPairing.h | 2 +- 4 files changed, 45 insertions(+), 32 deletions(-) diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.cpp b/libraries/Bluefruit52Lib/src/BLEConnection.cpp index 6daad956e..b1418aa81 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.cpp +++ b/libraries/Bluefruit52Lib/src/BLEConnection.cpp @@ -55,7 +55,8 @@ BLEConnection::BLEConnection(uint16_t conn_hdl, ble_gap_evt_connected_t const* e _hvn_sem = xSemaphoreCreateCounting(hvn_qsize, hvn_qsize); _wrcmd_sem = xSemaphoreCreateCounting(wrcmd_qsize, wrcmd_qsize); - _secured = false; + _sec_mode.sm = _sec_mode.lv = 1; // default to open + _bonded = false; _hvc_sem = NULL; _hvc_received = false; @@ -84,7 +85,7 @@ bool BLEConnection::connected(void) bool BLEConnection::paired (void) { - return _secured; + return secured(); } bool BLEConnection::bonded(void) @@ -94,7 +95,7 @@ bool BLEConnection::bonded(void) bool BLEConnection::secured(void) { - return _secured; + return !(_sec_mode.sm == 1 && _sec_mode.lv == 1); } uint8_t BLEConnection::getRole (void) @@ -132,6 +133,11 @@ uint16_t BLEConnection::getPeerName(char* buf, uint16_t bufsize) return Bluefruit.Gatt.readCharByUuid(_conn_hdl, BLEUuid(BLE_UUID_GAP_CHARACTERISTIC_DEVICE_NAME), buf, bufsize); } +ble_gap_conn_sec_mode_t BLEConnection::getSecureMode(void) +{ + return _sec_mode; +} + static inline bool is_tx_power_valid(int8_t power) { #if defined(NRF52832_XXAA) @@ -267,7 +273,7 @@ bool BLEConnection::removeBondKey(void) bool BLEConnection::requestPairing(void) { // skip if already paired - if ( _secured ) return true; + if ( secured() ) return true; return Bluefruit.Pairing._authenticate(_conn_hdl); } @@ -299,11 +305,11 @@ void BLEConnection::_eventHandler(ble_evt_t* evt) { const ble_gap_conn_sec_t* conn_sec = &evt->evt.gap_evt.params.conn_sec_update.conn_sec; + _sec_mode = conn_sec->sec_mode; + // Connection is secured (paired) if encryption level > 1 - if ( !( conn_sec->sec_mode.sm == 1 && conn_sec->sec_mode.lv == 1) ) + if ( this->secured() ) { - _secured = true; - // Try to restore CCCD with bonded peer, if it doesn't exist (newly bonded), initialize it if ( !loadCccd() ) sd_ble_gatts_sys_attr_set(_conn_hdl, NULL, 0, 0); } diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.h b/libraries/Bluefruit52Lib/src/BLEConnection.h index 7a0f402f3..db7497a27 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.h +++ b/libraries/Bluefruit52Lib/src/BLEConnection.h @@ -54,10 +54,11 @@ class BLEConnection uint16_t _ediv; bool _connected; - bool _secured; bool _bonded; // have LTK stored in InternalFS bool _hvc_received; + ble_gap_conn_sec_mode_t _sec_mode; + ble_gap_addr_t _peer_addr; // resolvable connect address ble_gap_addr_t _bond_id_addr; // address stored as bonded @@ -66,7 +67,6 @@ class BLEConnection // On-demand semaphore/data that are created on the fly SemaphoreHandle_t _hvc_sem; - SemaphoreHandle_t _pair_sem; public: BLEConnection(uint16_t conn_hdl, ble_gap_evt_connected_t const * evt_connected, uint8_t hvn_qsize, uint8_t wrcmd_qsize); @@ -87,6 +87,8 @@ class BLEConnection ble_gap_addr_t getPeerAddr(void); uint16_t getPeerName(char* buf, uint16_t bufsize); + ble_gap_conn_sec_mode_t getSecureMode(void); + bool disconnect(void); bool setTxPower(int8_t power); // set power for this connection diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.cpp b/libraries/Bluefruit52Lib/src/BLEPairing.cpp index be7711c96..c4b4e8b47 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.cpp +++ b/libraries/Bluefruit52Lib/src/BLEPairing.cpp @@ -33,6 +33,21 @@ #define LESC_SUPPORTED 0 #endif +// default is Just Work +static const ble_gap_sec_params_t _sec_param_default = +{ + .bond = 1, + .mitm = 0, + .lesc = LESC_SUPPORTED, + .keypress = 0, + .io_caps = BLE_GAP_IO_CAPS_NONE, + .oob = 0, + .min_key_size = 7, + .max_key_size = 16, + .kdist_own = { .enc = 1, .id = 1}, + .kdist_peer = { .enc = 1, .id = 1} +}; + //------------- IMPLEMENTATION -------------// // convert N-byte Number from Big <-> Little Endian to use with BLE @@ -50,20 +65,16 @@ static void swap_endian(uint8_t data[], uint32_t nbytes) } } -// default is Just Work -static const ble_gap_sec_params_t _sec_param_default = +static void _passkey_display_cabllack_dfr(BLEPairing::pair_passkey_cb_t func, uint16_t conn_hdl, uint8_t const passkey[6], bool match_request) { - .bond = 1, - .mitm = 0, - .lesc = LESC_SUPPORTED, - .keypress = 0, - .io_caps = BLE_GAP_IO_CAPS_NONE, - .oob = 0, - .min_key_size = 7, - .max_key_size = 16, - .kdist_own = { .enc = 1, .id = 1}, - .kdist_peer = { .enc = 1, .id = 1} -}; + bool matched = func(conn_hdl, passkey, match_request); + + if (match_request) + { + // Match request require to report the match (numberic comparison) + sd_ble_gap_auth_key_reply(conn_hdl, matched ? BLE_GAP_AUTH_KEY_TYPE_PASSKEY : BLE_GAP_AUTH_KEY_TYPE_NONE, NULL); + } +} BLEPairing::BLEPairing(void) { @@ -294,13 +305,7 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) // Invoke display callback if ( _passkey_cb ) { - bool matched = _passkey_cb(conn_hdl, passkey_display->passkey, passkey_display->match_request); - - if (passkey_display->match_request) - { - // Match request require to report the match (numberic comparison) - sd_ble_gap_auth_key_reply(conn_hdl, matched ? BLE_GAP_AUTH_KEY_TYPE_PASSKEY : BLE_GAP_AUTH_KEY_TYPE_NONE, NULL); - } + ada_callback(passkey_display->passkey, 6, _passkey_display_cabllack_dfr, _passkey_cb, conn_hdl, passkey_display->passkey, passkey_display->match_request); } } break; @@ -392,9 +397,9 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) const ble_gap_conn_sec_t* conn_sec = &evt->evt.gap_evt.params.conn_sec_update.conn_sec; LOG_LV2("PAIR", "Security Mode = %d, Level = %d", conn_sec->sec_mode.sm, conn_sec->sec_mode.lv); - if ( conn->secured() && _secured_cb ) + if ( _secured_cb ) { - ada_callback(NULL, 0, _secured_cb, conn_hdl, conn_sec->sec_mode.sm, conn_sec->sec_mode.lv); + ada_callback(NULL, 0, _secured_cb, conn_hdl); } } break; diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.h b/libraries/Bluefruit52Lib/src/BLEPairing.h index 9c17f8b9d..57705bf4a 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.h +++ b/libraries/Bluefruit52Lib/src/BLEPairing.h @@ -37,7 +37,7 @@ class BLEPairing public: typedef bool (*pair_passkey_cb_t ) (uint16_t conn_hdl, uint8_t const passkey[6], bool match_request); typedef void (*pair_complete_cb_t) (uint16_t conn_hdl, uint8_t auth_status); - typedef void (*pair_secured_cb_t) (uint16_t conn_hdl, uint8_t sec_mode, uint8_t level); + typedef void (*pair_secured_cb_t) (uint16_t conn_hdl); BLEPairing(void); From a1ab1a3498df2c52b29961d307d8fcf05321429a Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 18 Mar 2020 14:23:11 +0700 Subject: [PATCH 50/74] added central pairing example --- .../central_pairing/central_pairing.ino | 406 ++++++++++++++++++ 1 file changed, 406 insertions(+) create mode 100644 libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino diff --git a/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino b/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino new file mode 100644 index 000000000..c0341e579 --- /dev/null +++ b/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino @@ -0,0 +1,406 @@ +/********************************************************************* + This is an example for our nRF52 based Bluefruit LE modules + + Pick one up today in the adafruit shop! + + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +#include + +/* This sketch demonstrates Pairing process using dynamic Passkey. + * This sketch is essentially the same as bleuart.ino except the BLE Uart + * service requires Security Mode with Man-In-The-Middle protection i.e + * + * BLE Pairing procedure is complicated, it is advisable for users to go through + * these articles to get familiar with the procedure and terminology + * - https://www.bluetooth.com/blog/bluetooth-pairing-part-1-pairing-feature-exchange/ + * - https://www.bluetooth.com/blog/bluetooth-pairing-part-2-key-generation-methods/ + * - https://www.bluetooth.com/blog/bluetooth-pairing-passkey-entry/ + * - https://www.bluetooth.com/blog/bluetooth-pairing-part-4/ + */ + +#define TFT_NO_DISPLAY 0 +#define TFT_GIZMO 1 // used with Circuit Playground Bluefruit +#define TFT_CLUE 2 // CLUE's on-board display +#define TFT_24_FEATHERWING 3 +#define TFT_35_FEATHERWING 4 + + +#if defined(ARDUINO_NRF52840_CIRCUITPLAY) + // Circuit Playground Bluefruit use with TFT GIZMO + #define TFT_IN_USE TFT_GIZMO + #define DEVICE_NAME "CPLAY" + + #include "Adafruit_ST7789.h" + Adafruit_ST7789 tft = Adafruit_ST7789(&SPI, 0, 1, -1); // CS = 0, DC = 1 + +#elif defined(ARDUINO_NRF52840_CLUE) + // CLUE use on-board TFT + #define TFT_IN_USE TFT_CLUE + #define DEVICE_NAME "CLUE" + + #include "Adafruit_ST7789.h" + Adafruit_ST7789 tft = Adafruit_ST7789(&SPI1, PIN_TFT_CS, PIN_TFT_DC, PIN_TFT_RST); + +#else + // [Configurable] For other boards please select which external display to match your hardware setup + #define TFT_IN_USE TFT_24_FEATHERWING + #define DEVICE_NAME "Feather" + + #if defined(ARDUINO_NRF52832_FEATHER) + // Feather nRF52832 pin map is different from others + #define TFT_DC 11 + #define TFT_CS 31 + #else + // Default for others + #define TFT_DC 10 + #define TFT_CS 9 + #endif + + #if TFT_IN_USE == TFT_35_FEATHERWING + #include "Adafruit_HX8357.h" + Adafruit_HX8357 tft = Adafruit_HX8357(TFT_CS, TFT_DC); + + #elif TFT_IN_USE == TFT_24_FEATHERWING + #include + Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); + #endif // TFT + +#endif // board variants + + +#define COLOR_WHITE 0xFFFF +#define COLOR_BLACK 0x0000 +#define COLOR_YELLOW 0xFFE0 +#define COLOR_GREEN 0x07E0 +#define COLOR_RED 0xF800 + +BLEClientUart clientUart; // bleuart client + +void setup() +{ + Serial.begin(115200); + + Serial.println("Bluefruit52 Central Pairing Example"); + Serial.println("-----------------------------------\n"); + +#if TFT_IN_USE == TFT_CLUE + tft.init(240, 240); + tft.setRotation(1); + + // Screen refresh rate control (datasheet 9.2.18, FRCTRL2) + uint8_t rtna = 0x01; + tft.sendCommand(0xC6, &rtna, 1);; + + // turn back light on + uint8_t backlight = PIN_TFT_LITE; + pinMode(backlight, OUTPUT); + digitalWrite(backlight, HIGH); + +#elif TFT_IN_USE == TFT_GIZMO + tft.init(240, 240); + tft.setRotation(2); + + // turn back light on + uint8_t backlight = A3; + pinMode(backlight, OUTPUT); + digitalWrite(backlight, HIGH); + +#elif TFT_IN_USE != TFT_NO_DISPLAY + tft.begin(); + +#endif // TFT + + pinMode(PIN_BUTTON1, INPUT_PULLUP); + pinMode(PIN_BUTTON2, INPUT_PULLUP); + + // Initialize Bluefruit with maximum connections as Peripheral = 0, Central = 1 + // SRAM usage required by SoftDevice will increase dramatically with number of connections + Bluefruit.begin(0, 1); + Bluefruit.setName("Bluefruit52 Central"); + + // clear bonds if BUTTON A is pressed + Serial.println("Hold button A to clear bonds ..... "); + delay(2000); + if (0 == digitalRead(PIN_BUTTON1)) + { + Serial.println("Clear all central bonds"); + Bluefruit.Central.clearBonds(); + } + + // To use dynamic PassKey for pairing, we need to have + // - IO capacities at least DISPPLAY + // - Register callback to display/print dynamic passkey for central + // For complete mapping of the IO Capabilities to Key Generation Method, check out this article + // https://www.bluetooth.com/blog/bluetooth-pairing-part-2-key-generation-methods/ + Bluefruit.Pairing.setIOCaps(true, true, false); // display = true, yes/no = true, keyboard = false + Bluefruit.Pairing.setPasskeyCallback(pairing_passkey_callback); + + // Set complete callback to print the pairing result + Bluefruit.Pairing.setCompleteCallback(pairing_complete_callback); + + // Set connection secured callback, invoked when connection is encrypted + Bluefruit.Pairing.setSecuredCallback(connection_secured_callback); + + // Init BLE Central Uart Serivce + clientUart.begin(); + clientUart.setRxCallback(bleuart_rx_callback); + + // Increase Blink rate to different from PrPh advertising mode + Bluefruit.setConnLedInterval(250); + + // Callbacks for Central + Bluefruit.Central.setConnectCallback(connect_callback); + Bluefruit.Central.setDisconnectCallback(disconnect_callback); + +#if TFT_IN_USE != TFT_NO_DISPLAY + tft.fillScreen(COLOR_BLACK); + tft.setTextColor(COLOR_WHITE); + tft.setTextSize(2); + tft.setCursor(0, 0); + tft.print("Scanning..."); +#endif + + /* Start Central Scanning + * - Enable auto scan if disconnected + * - Interval = 100 ms, window = 80 ms + * - Don't use active scan + * - Start(timeout) with timeout = 0 will scan forever (until connected) + */ + Bluefruit.Scanner.setRxCallback(scan_callback); + Bluefruit.Scanner.restartOnDisconnect(true); + Bluefruit.Scanner.setInterval(160, 80); // in unit of 0.625 ms + Bluefruit.Scanner.useActiveScan(false); + Bluefruit.Scanner.start(0); // // 0 = Don't stop scanning after n seconds +} + +/** + * Callback invoked when scanner pick up an advertising data + * @param report Structural advertising data + */ +void scan_callback(ble_gap_evt_adv_report_t* report) +{ + // Check if advertising contain BleUart service + if ( Bluefruit.Scanner.checkReportForService(report, clientUart) ) + { + Serial.print("BLE UART service detected. Connecting ... "); + + // Connect to device with bleuart service in advertising + Bluefruit.Central.connect(report); + }else + { + // For Softdevice v6: after received a report, scanner will be paused + // We need to call Scanner resume() to continue scanning + Bluefruit.Scanner.resume(); + } +} + +/** + * Callback invoked when an connection is established + * @param conn_handle + */ +void connect_callback(uint16_t conn_handle) +{ + BLEConnection* conn = Bluefruit.Connection(conn_handle); + + Serial.println("Connected"); + +#if TFT_IN_USE != TFT_NO_DISPLAY + tft.println("connected"); +#endif + + // If we are not bonded with peer previously -> send pairing request + // Else wait for the connection secured callback + if ( !conn->bonded() ) + { + conn->requestPairing(); + } +} + +/** + * Callback invoked when a connection is dropped + * @param conn_handle + * @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h + */ +void disconnect_callback(uint16_t conn_handle, uint8_t reason) +{ + (void) conn_handle; + (void) reason; + + Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX); +} + +/** + * Callback invoked when uart received data + * @param uart_svc Reference object to the service where the data + * arrived. In this example it is clientUart + */ +void bleuart_rx_callback(BLEClientUart& uart_svc) +{ + Serial.print("[RX]: "); + + while ( uart_svc.available() ) + { + Serial.print( (char) uart_svc.read() ); + } + + Serial.println(); +} + +bool pairing_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6], bool match_request) +{ + Serial.println("Pairing Passkey"); + Serial.printf(" %.3s %.3s\n\n", passkey, passkey+3); + +#if TFT_IN_USE != TFT_NO_DISPLAY + tft.fillScreen(COLOR_BLACK); + tft.println("Pairing Passkey\n"); + tft.setTextColor(COLOR_YELLOW); + tft.setTextSize(4); + tft.printf(" %.3s %.3s\n", passkey, passkey+3); + + tft.setTextColor(COLOR_WHITE); + tft.setTextSize(2); +#endif + + if (match_request) + { + Serial.println("Do you want to pair ?"); + Serial.println("Press Button A to accept, Button B to reject"); + + #if TFT_IN_USE != TFT_NO_DISPLAY + tft.println("\nDo you accept ?\n\n"); + + tft.setTextSize(3); + tft.setTextColor(COLOR_GREEN); + tft.print("<< Yes"); + tft.setTextColor(COLOR_RED); + tft.println(" No >>"); + + tft.setTextColor(COLOR_WHITE); + tft.setTextSize(2); + tft.println(); + #endif + + // wait until either button is pressed + uint32_t start_time = millis(); + while( digitalRead(PIN_BUTTON1) && digitalRead(PIN_BUTTON2) ) + { + // 30 seconds timeout + if ( millis() > start_time + 30000 ) break; + } + + // A = accept + if ( 0 == digitalRead(PIN_BUTTON1) ) return true; + + // B = reject + if ( 0 == digitalRead(PIN_BUTTON2) ) return false; + + return false; + } + + return true; +} + +void pairing_complete_callback(uint16_t conn_handle, uint8_t auth_status) +{ + if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS) + { + Serial.println("Succeeded"); + }else + { + Serial.println("Failed"); + } + +#if TFT_IN_USE != TFT_NO_DISPLAY + if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS) + { + tft.setTextColor(COLOR_GREEN); + tft.print("Succeeded "); + }else + { + tft.setTextColor(COLOR_RED); + tft.print("Failed "); + } + + tft.setTextColor(COLOR_WHITE); + tft.setTextSize(2); +#endif +} + +void connection_secured_callback(uint16_t conn_handle) +{ + BLEConnection* conn = Bluefruit.Connection(conn_handle); + + if ( !conn->secured() ) + { + // It is possible that connection is still not secured by this time. + // This happens when we try to encrypt connection using stored bond keys + // but peer reject it (probably it remove its stored key). + // Therefore we will request an pairing again --> callback again when encrypted + conn->requestPairing(); + } + else + { + Serial.println(" Secured"); + + #if TFT_IN_USE != TFT_NO_DISPLAY + tft.setTextColor(COLOR_YELLOW); + tft.println("secured"); + tft.setTextColor(COLOR_WHITE); + #endif + + Serial.print("Discovering BLE Uart Service ... "); + if ( clientUart.discover(conn_handle) ) + { + Serial.println("Found it"); + + Serial.println("Enable TXD's notify"); + clientUart.enableTXD(); + + Serial.println("Ready to receive from peripheral"); + }else + { + Serial.println("Found NONE"); + + // disconnect since we couldn't find bleuart service + Bluefruit.disconnect(conn_handle); + } + } +} + +void loop() +{ + uint16_t const conn_handle = 0; // this example only support 1 connection + BLEConnection* conn = Bluefruit.Connection(conn_handle); + + // skip if connection not exist or not connected + if ( !conn && conn->connected() ) return; + + // In this example we only read & write when connection is secured + if ( conn->secured() ) + { + // Not discovered yet + if ( clientUart.discovered() ) + { + // Discovered means in working state + // Get Serial input and send to Peripheral + if ( Serial.available() ) + { + delay(2); // delay a bit for all characters to arrive + + char str[20+1] = { 0 }; + Serial.readBytes(str, 20); + + clientUart.print( str ); + } + } + } +} From ec3257bd2e53e0cd143c1d3cd35e5bda594b0520 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 18 Mar 2020 14:44:37 +0700 Subject: [PATCH 51/74] clean up example --- .../central_pairing/central_pairing.ino | 19 +++-- .../pairing_display/pairing_display.ino | 78 ++++++++++++------- 2 files changed, 63 insertions(+), 34 deletions(-) diff --git a/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino b/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino index c0341e579..931e478ff 100644 --- a/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino +++ b/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino @@ -165,7 +165,7 @@ void setup() tft.setTextColor(COLOR_WHITE); tft.setTextSize(2); tft.setCursor(0, 0); - tft.print("Scanning..."); + tft.println("Scanning ..."); #endif /* Start Central Scanning @@ -213,7 +213,10 @@ void connect_callback(uint16_t conn_handle) Serial.println("Connected"); #if TFT_IN_USE != TFT_NO_DISPLAY - tft.println("connected"); + tft.fillScreen(COLOR_BLACK); + tft.setTextSize(2); + tft.setCursor(0, 0); + tft.println("Connected"); #endif // If we are not bonded with peer previously -> send pairing request @@ -235,6 +238,10 @@ void disconnect_callback(uint16_t conn_handle, uint8_t reason) (void) reason; Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX); + +#if TFT_IN_USE != TFT_NO_DISPLAY + tft.println("Scanning ..."); +#endif } /** @@ -244,14 +251,10 @@ void disconnect_callback(uint16_t conn_handle, uint8_t reason) */ void bleuart_rx_callback(BLEClientUart& uart_svc) { - Serial.print("[RX]: "); - while ( uart_svc.available() ) { Serial.print( (char) uart_svc.read() ); } - - Serial.println(); } bool pairing_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6], bool match_request) @@ -342,14 +345,14 @@ void connection_secured_callback(uint16_t conn_handle) if ( !conn->secured() ) { // It is possible that connection is still not secured by this time. - // This happens when we try to encrypt connection using stored bond keys + // This happens (central only) when we try to encrypt connection using stored bond keys // but peer reject it (probably it remove its stored key). // Therefore we will request an pairing again --> callback again when encrypted conn->requestPairing(); } else { - Serial.println(" Secured"); + Serial.println("Secured"); #if TFT_IN_USE != TFT_NO_DISPLAY tft.setTextColor(COLOR_YELLOW); diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino index 999738494..0c105ef31 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino @@ -149,6 +149,15 @@ void setup() Bluefruit.setTxPower(4); // Check bluefruit.h for supported values Bluefruit.setName(DEVICE_NAME); + // clear bonds if BUTTON A is pressed + Serial.println("Hold button A to clear bonds ..... "); + delay(2000); + if (0 == digitalRead(PIN_BUTTON1)) + { + Serial.println("Clear all central bonds"); + Bluefruit.Periph.clearBonds(); + } + // To use dynamic PassKey for pairing, we need to have // - IO capacities at least DISPPLAY // - Register callback to display/print dynamic passkey for central @@ -160,6 +169,9 @@ void setup() // Set complete callback to print the pairing result Bluefruit.Pairing.setCompleteCallback(pairing_complete_callback); + // Set connection secured callback, invoked when connection is encrypted + Bluefruit.Pairing.setSecuredCallback(connection_secured_callback); + Bluefruit.Periph.setConnectCallback(connect_callback); Bluefruit.Periph.setDisconnectCallback(disconnect_callback); @@ -170,19 +182,20 @@ void setup() bleuart.setPermission(SECMODE_ENC_WITH_MITM); bleuart.begin(); - // Set up and start advertising - startAdv(); - - Serial.println("Please use Adafruit's Bluefruit LE app to connect in UART mode"); - Serial.println("Your phone should pop-up PIN input"); - Serial.println("Once connected, enter character(s) that you wish to send"); - #if TFT_IN_USE != TFT_NO_DISPLAY tft.fillScreen(COLOR_BLACK); tft.setTextColor(COLOR_WHITE); tft.setTextSize(2); - tft.println("Advertising ... "); + tft.setCursor(0, 0); + tft.print("Advertising..."); #endif + + Serial.println("Please use Adafruit's Bluefruit LE app to connect in UART mode"); + Serial.println("Your phone should pop-up PIN input"); + Serial.println("Once connected, enter character(s) that you wish to send"); + + // Set up and start advertising + startAdv(); } void startAdv(void) @@ -235,6 +248,27 @@ void loop() } } + +// callback invoked when central connects +void connect_callback(uint16_t conn_handle) +{ + // Get the reference to current connection + BLEConnection* connection = Bluefruit.Connection(conn_handle); + + char central_name[32] = { 0 }; + connection->getPeerName(central_name, sizeof(central_name)); + + Serial.print("Connected to "); + Serial.println(central_name); + +#if TFT_IN_USE != TFT_NO_DISPLAY + tft.fillScreen(COLOR_BLACK); + tft.setTextSize(2); + tft.setCursor(0, 0); + tft.println("Connected"); +#endif +} + // callback invoked when pairing passkey is generated // - passkey: 6 keys (without null terminator) for displaying // - match_request: true when authentication method is Numberic Comparison. @@ -273,6 +307,7 @@ bool pairing_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6], bo tft.setTextColor(COLOR_WHITE); tft.setTextSize(2); + tft.println(); #endif // wait until either button is pressed @@ -308,7 +343,7 @@ void pairing_complete_callback(uint16_t conn_handle, uint8_t auth_status) Serial.println("Failed"); } -#if TFT_IN_USE != TFT_NO_DISPLAY + #if TFT_IN_USE != TFT_NO_DISPLAY if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS) { tft.setTextColor(COLOR_GREEN); @@ -321,27 +356,18 @@ void pairing_complete_callback(uint16_t conn_handle, uint8_t auth_status) tft.setTextColor(COLOR_WHITE); tft.setTextSize(2); -#endif + #endif } -// callback invoked when central connects -void connect_callback(uint16_t conn_handle) +void connection_secured_callback(uint16_t conn_handle) { - // Get the reference to current connection - BLEConnection* connection = Bluefruit.Connection(conn_handle); + Serial.println("Secured"); - char central_name[32] = { 0 }; - connection->getPeerName(central_name, sizeof(central_name)); - - Serial.print("Connected to "); - Serial.println(central_name); - -#if TFT_IN_USE != TFT_NO_DISPLAY - tft.fillScreen(COLOR_BLACK); - tft.setTextSize(2); - tft.setCursor(0, 0); - tft.println("Connected"); -#endif + #if TFT_IN_USE != TFT_NO_DISPLAY + tft.setTextColor(COLOR_YELLOW); + tft.println("secured"); + tft.setTextColor(COLOR_WHITE); + #endif } /** From f92ed9176eec42bc15df0011ad7ab0d47ec0c6b2 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 18 Mar 2020 16:58:52 +0700 Subject: [PATCH 52/74] added ancs_arcada example work with CLUE & CPB + GIZMO --- .../Peripheral/ancs_arcada/ancs_arcada.ino | 407 ++++++++++++++++++ 1 file changed, 407 insertions(+) create mode 100644 libraries/Bluefruit52Lib/examples/Peripheral/ancs_arcada/ancs_arcada.ino diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/ancs_arcada/ancs_arcada.ino b/libraries/Bluefruit52Lib/examples/Peripheral/ancs_arcada/ancs_arcada.ino new file mode 100644 index 000000000..f5abcd59e --- /dev/null +++ b/libraries/Bluefruit52Lib/examples/Peripheral/ancs_arcada/ancs_arcada.ino @@ -0,0 +1,407 @@ +/********************************************************************* + This is an example for our nRF52 based Bluefruit LE modules + + Pick one up today in the adafruit shop! + + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +/* + * This sketch is similar to 'ancs', but it also uses a Feather OLED + * Wing to display incoming ANCS alerts: + * https://www.adafruit.com/product/2900 + * + * BUTTON A: Up or accept call + * BUTTON B: Not used since it is hard to press + * BUTTON C: Down or decline call + */ +#include +#include + +Adafruit_Arcada arcada; +Adafruit_SPITFT* tft; + +/*------------- Notification List -------------*/ +#define MAX_COUNT 20 +#define BUFSIZE 64 + +typedef struct +{ + AncsNotification_t ntf; + char title[BUFSIZE]; + char message[BUFSIZE]; + char app_name[BUFSIZE]; +} MyNotif_t; + +MyNotif_t myNotifs[MAX_COUNT] = { 0 }; + +// Number of notifications +int notifCount = 0; + +/*------------- Display Management -------------*/ +#define ONSCREEN_TIME 10000 // On-screen time for each notification + +int activeIndex = 0; // Index of currently displayed notification +int displayIndex = -1; // Index of notification about to display + +uint32_t drawTime = 0; // Last time oled display notification + +/*------------- BLE Client Service-------------*/ +BLEAncs bleancs; + +void setup() +{ + arcada.arcadaBegin(); + arcada.displayBegin(); + arcada.setBacklight(255); + + tft = arcada.display; + tft->setCursor(0, 0); + tft->setTextWrap(true); + tft->setTextSize(2); + + tft->println("Advertising..."); + + // Config the peripheral connection with maximum bandwidth + // more SRAM required by SoftDevice + // Note: All config***() function must be called before begin() + Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); + + Bluefruit.begin(); + Bluefruit.setTxPower(4); // Check bluefruit.h for supported values + Bluefruit.Periph.setConnectCallback(connect_callback); + Bluefruit.Periph.setDisconnectCallback(disconnect_callback); + + // Set connection secured callback, invoked when connection is encrypted + Bluefruit.Pairing.setSecuredCallback(connection_secured_callback); + + // Configure and Start Service + bleancs.begin(); + bleancs.setNotificationCallback(ancs_notification_callback); + + // Set up and start advertising + startAdv(); +} + +void startAdv(void) +{ + // Advertising packet + Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); + Bluefruit.Advertising.addTxPower(); + + // Include ANCS 128-bit uuid + Bluefruit.Advertising.addService(bleancs); + + // Secondary Scan Response packet (optional) + // Since there is no room for 'Name' in Advertising packet + Bluefruit.ScanResponse.addName(); + + /* Start Advertising + * - Enable auto advertising if disconnected + * - Interval: fast mode = 20 ms, slow mode = 152.5 ms + * - Timeout for fast mode is 30 seconds + * - Start(timeout) with timeout = 0 will advertise forever (until connected) + * + * For recommended advertising interval + * https://developer.apple.com/library/content/qa/qa1931/_index.html + */ + Bluefruit.Advertising.restartOnDisconnect(true); + Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms + Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode + Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds +} + +void loop() +{ + // This example only support 1 connection + uint16_t const conn_handle = 0; + BLEConnection* conn = Bluefruit.Connection(conn_handle); + + // connection exist, connected, and secured + if ( !(conn && conn->connected() && conn->secured()) ) return; + + // If service is not yet discovered + if ( !bleancs.discovered() ) return; + + // No notifications, do nothing + if ( notifCount == 0 ) return; + + arcada.readButtons(); + uint8_t const justReleased = arcada.justReleasedButtons(); + uint8_t buttonLeft = (justReleased & ARCADA_BUTTONMASK_LEFT); + uint8_t buttonRight = (justReleased & ARCADA_BUTTONMASK_RIGHT); + +#ifdef ARDUINO_NRF52840_CLUE + // swap button left & right on CLUE since the screen is on opposite side + uint8_t temp = buttonLeft; + buttonLeft = buttonRight; + buttonRight = temp; +#endif + + if ( myNotifs[activeIndex].ntf.categoryID == ANCS_CAT_INCOMING_CALL ) + { + /* Incoming call event + * - Button A to accept call + * - Button B to decline call + */ + if ( buttonLeft ) bleancs.actPositive(myNotifs[activeIndex].ntf.uid); + if ( buttonRight ) bleancs.actNegative(myNotifs[activeIndex].ntf.uid); + } + else + { + /* Normal events navigation (wrap around) + * - Button A to display previous notification + * - Button B to display next notification + * + * When a notification is display ONSCREEN_TIME, + * we will display the next one + */ + if ( buttonLeft ) + { + displayIndex = (activeIndex != 0) ? (activeIndex-1) : (notifCount-1) ; + } + + if ( buttonRight ) + { + displayIndex = (activeIndex != (notifCount-1)) ? (activeIndex + 1) : 0; + } + + // Display requested notification + if ( displayIndex >= 0 ) + { + activeIndex = displayIndex; + displayIndex = -1; + + displayNotification(activeIndex); + drawTime = millis(); // Save time we draw + } + // Display next notification if time is up + else if ( drawTime + ONSCREEN_TIME < millis() ) + { + activeIndex = (activeIndex+1)%notifCount; + + displayNotification(activeIndex); + drawTime = millis(); // Save time we draw + } + } +} + +/** + * Display notification contents to oled screen + * @param index index of notification + */ +void displayNotification(int index) +{ + // safeguard + if ( index < 0 || (index >= notifCount) ) return; + + // let's Turn on and off RED LED when we draw to get attention + digitalWrite(LED_BUILTIN, HIGH); + + /*------------- Display to OLED -------------*/ + MyNotif_t* myNtf = &myNotifs[index]; + + tft->fillScreen(ARCADA_BLACK); + tft->setCursor(0, 0); + + tft->setTextSize(3); + tft->setTextColor(ARCADA_GREEN); + tft->println(myNtf->app_name); + tft->println(); + + // Incoming call event, display a bit differently + if ( myNtf->ntf.categoryID == ANCS_CAT_INCOMING_CALL ) + { + tft->setTextColor(ARCADA_YELLOW); + tft->println(myNtf->title); + tft->println(); + + tft->println("calling ..."); + tft->println(); + + tft->setTextSize(2); + tft->setTextColor(ARCADA_GREEN); + tft->print("< Answer"); + tft->setTextColor(ARCADA_RED); + tft->println(" Reject >"); + }else + { + tft->setTextSize(2); + tft->setTextColor(ARCADA_GREENYELLOW); + tft->printf("%02d/%02d\n", index+1, notifCount); + tft->println(); + + tft->setTextColor(ARCADA_YELLOW); + tft->println(myNtf->title); + tft->println(); + + tft->setTextColor(ARCADA_WHITE); + tft->println(myNtf->message); + tft->println(); + } + + digitalWrite(LED_BUILTIN, LOW); +} + +/** + * Connect Callback + * Perform ANCS discovering, request Pairing + */ +void connect_callback(uint16_t conn_handle) +{ + BLEConnection* conn = Bluefruit.Connection(conn_handle); + + tft->println("Connected"); + tft->print("Discovering ... "); + + if ( bleancs.discover( conn_handle ) ) + { + tft->println("OK"); + + // ANCS requires secured connection + // request Pairing if not bonded + tft->print("Paring ... "); + conn->requestPairing(); + }else + { + // disconnect if couldn't find ancs service + conn->disconnect(); + tft->println("Failed"); + } +} + +void connection_secured_callback(uint16_t conn_handle) +{ + BLEConnection* conn = Bluefruit.Connection(conn_handle); + + if ( !conn->secured() ) + { + // It is possible that connection is still not secured by this time. + // This happens (central only) when we try to encrypt connection using stored bond keys + // but peer reject it (probably it remove its stored key). + // Therefore we will request an pairing again --> callback again when encrypted + conn->requestPairing(); + } + else + { + Serial.println("Secured"); + + tft->println("Secured"); + + if ( bleancs.discovered() ) + { + bleancs.enableNotification(); + tft->println("Ready to receive"); + } + } +} + +/** + * Notification callback + * @param notif Notification from iDevice + * + * Save/Modify notification into myNotifs struct to display later + */ +void ancs_notification_callback(AncsNotification_t* notif) +{ + if (notif->eventID == ANCS_EVT_NOTIFICATION_ADDED ) + { + myNotifs[ notifCount ].ntf = *notif; + + /*------------- Retrieve Title, Message, App Name -------------*/ + MyNotif_t* myNtf = &myNotifs[notifCount]; + uint32_t uid = myNtf->ntf.uid; + + // iDevice often include Unicode "Bidirection Text Control" in the Title. + // Mostly are U+202D as beginning and U+202C as ending. Let's remove them + if ( bleancs.getTitle (uid, myNtf->title , BUFSIZE) ) + { + char u202D[3] = { 0xE2, 0x80, 0xAD }; // U+202D in UTF-8 + char u202C[3] = { 0xE2, 0x80, 0xAC }; // U+202C in UTF-8 + + int len = strlen(myNtf->title); + + if ( 0 == memcmp(&myNtf->title[len-3], u202C, 3) ) + { + len -= 3; + myNtf->title[len] = 0; // chop ending U+202C + } + + if ( 0 == memcmp(myNtf->title, u202D, 3) ) + { + memmove(myNtf->title, myNtf->title+3, len-2); // move null-terminator as well + } + } + + bleancs.getMessage(uid, myNtf->message , BUFSIZE); + bleancs.getAppName(uid, myNtf->app_name, BUFSIZE); + + displayIndex = notifCount++; // display new notification + }else if (notif->eventID == ANCS_EVT_NOTIFICATION_REMOVED ) + { + for(int i=0; iuid == myNotifs[i].ntf.uid ) + { + // remove by swapping with the last one + notifCount--; + myNotifs[i] = myNotifs[notifCount]; + + // Invalid removed data + memset(&myNotifs[notifCount], 0, sizeof(MyNotif_t)); + + if (activeIndex == notifCount) + { + // If remove the last notification, adjust display index + displayIndex = notifCount-1; + }else if (activeIndex == i) + { + // Re-draw if remove currently active one + displayIndex = activeIndex; + } + + break; + } + } + }else + { + // Modification + for(int i=0; iuid == myNotifs[i].ntf.uid ) + { + // Display modification + displayIndex = i; + break; + } + } + } +} + +/** + * Callback invoked when a connection is dropped + * @param conn_handle connection where this event happens + * @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h + */ +void disconnect_callback(uint16_t conn_handle, uint8_t reason) +{ + (void) conn_handle; + (void) reason; + + // reset notification array + notifCount = 0; + activeIndex = 0; + displayIndex = -1; + + memset(myNotifs, 0, sizeof(myNotifs)); + + tft->fillScreen(ARCADA_BLACK); + tft->setCursor(0, 0); + tft->println("Not connected"); +} From b5f2e746c1671cbea65df7e18ac4d77912b8470f Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 18 Mar 2020 17:46:35 +0700 Subject: [PATCH 53/74] clean up ancs example --- .../examples/Peripheral/ancs/ancs.ino | 108 +++++++++++------- .../Peripheral/ancs_arcada/ancs_arcada.ino | 2 +- 2 files changed, 69 insertions(+), 41 deletions(-) diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/ancs/ancs.ino b/libraries/Bluefruit52Lib/examples/Peripheral/ancs/ancs.ino index b30104d7e..6719c4e82 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/ancs/ancs.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/ancs/ancs.ino @@ -23,7 +23,8 @@ BLEClientDis bleClientDis; BLEAncs bleancs; -char buffer[128]; +#define BUFSIZE 128 +char buffer[BUFSIZE]; // Check BLEAncs.h for AncsNotification_t const char* EVENT_STR[] = { "Added", "Modified", "Removed" }; @@ -37,7 +38,7 @@ const char* CAT_STR [] = void setup() { Serial.begin(115200); - while ( !Serial ) delay(10); // for nrf52840 with native usb +// while ( !Serial ) delay(10); // for nrf52840 with native usb Serial.println("Bluefruit52 BLE ANCS Example"); Serial.println("----------------------------\n"); @@ -52,10 +53,12 @@ void setup() Bluefruit.begin(); Bluefruit.setTxPower(4); // Check bluefruit.h for supported values - Bluefruit.setName("Bluefruit52"); Bluefruit.Periph.setConnectCallback(connect_callback); Bluefruit.Periph.setDisconnectCallback(disconnect_callback); + // Set connection secured callback, invoked when connection is encrypted + Bluefruit.Pairing.setSecuredCallback(connection_secured_callback); + // Configure DIS client bleClientDis.begin(); @@ -108,6 +111,8 @@ void loop() void connect_callback(uint16_t conn_handle) { + BLEConnection* conn = Bluefruit.Connection(conn_handle); + Serial.println("Connected"); Serial.print("Discovering DIS ... "); @@ -116,16 +121,16 @@ void connect_callback(uint16_t conn_handle) Serial.println("Discovered"); // Read and print Manufacturer string - memset(buffer, 0, sizeof(buffer)); - if ( bleClientDis.getManufacturer(buffer, sizeof(buffer)) ) + memset(buffer, 0, BUFSIZE); + if ( bleClientDis.getManufacturer(buffer, BUFSIZE) ) { Serial.print("Manufacturer: "); Serial.println(buffer); } // Read and print Model Number string - memset(buffer, 0, sizeof(buffer)); - if ( bleClientDis.getModel(buffer, sizeof(buffer)) ) + memset(buffer, 0, BUFSIZE); + if ( bleClientDis.getModel(buffer, BUFSIZE) ) { Serial.print("Model: "); Serial.println(buffer); @@ -141,54 +146,77 @@ void connect_callback(uint16_t conn_handle) // ANCS requires pairing to work, it makes sense to request security here as well Serial.print("Attempting to PAIR with the iOS device, please press PAIR on your phone ... "); - if ( Bluefruit.requestPairing(conn_handle) ) + conn->requestPairing(); + } +} + +void connection_secured_callback(uint16_t conn_handle) +{ + BLEConnection* conn = Bluefruit.Connection(conn_handle); + + if ( !conn->secured() ) + { + // It is possible that connection is still not secured by this time. + // This happens (central only) when we try to encrypt connection using stored bond keys + // but peer reject it (probably it remove its stored key). + // Therefore we will request an pairing again --> callback again when encrypted + conn->requestPairing(); + } + else + { + Serial.println("Secured"); + + if ( bleancs.discovered() ) { - Serial.println("Done"); Serial.println("Enabling notifications"); Serial.println(); bleancs.enableNotification(); - - Serial.println("| Event | Category (count) | Title | Message | App ID | App Name |"); - Serial.println("---------------------------------------------------------------------------------------------------------------"); } } } void ancs_notification_callback(AncsNotification_t* notif) { - int n; - Serial.printf("| %-8s | ", EVENT_STR[notif->eventID]); + uint32_t const uid = notif->uid; + + // Application ID & Name + char appID[128] = { 0 }; + bleancs.getAppID(uid, appID, sizeof(appID)); - // Print Category with padding - n = Serial.printf("%s (%d)", CAT_STR[notif->categoryID], notif->categoryCount); - for (int i=n; i<20; i++) Serial.print(' '); - Serial.print(" | "); + memset(buffer, 0, BUFSIZE); + bleancs.getAppAttribute(appID, ANCS_APP_ATTR_DISPLAY_NAME, buffer, BUFSIZE); + + Serial.printf("%-15s (%s)\n", buffer, appID); // Get notification Title - // iDevice often includes Unicode "Bidirection Text Control" in the Title. - // Most strings have U+202D at the beginning and U+202C at the end. You may - // want to remove them. - // U+202D is E2-80-AD, U+202C is E2-80-AC in UTF-8 - memset(buffer, 0, sizeof(buffer)); - bleancs.getAttribute(notif->uid, ANCS_ATTR_TITLE, buffer, sizeof(buffer)); - Serial.printf("%-14s | ", buffer); + // iDevice often include Unicode "Bidirection Text Control" in the Title. + // Mostly are U+202D as beginning and U+202C as ending. Let's remove them + memset(buffer, 0, BUFSIZE); + if ( bleancs.getTitle(uid, buffer, BUFSIZE) ) + { + char u202D[3] = { 0xE2, 0x80, 0xAD }; // U+202D in UTF-8 + char u202C[3] = { 0xE2, 0x80, 0xAC }; // U+202C in UTF-8 + + int len = strlen(buffer); + + if ( 0 == memcmp(&buffer[len-3], u202C, 3) ) + { + len -= 3; + buffer[len] = 0; // chop ending U+202C + } + + if ( 0 == memcmp(buffer, u202D, 3) ) + { + memmove(buffer, buffer+3, len-2); // move null-terminator as well + } + } + Serial.printf("%-15s %s\n", buffer, EVENT_STR[notif->eventID]); + // Get notification Message - memset(buffer, 0, sizeof(buffer)); - bleancs.getAttribute(notif->uid, ANCS_ATTR_MESSAGE, buffer, sizeof(buffer)); - Serial.printf("%-15s | ", buffer); - - // Get App ID and store in the app_id variable - char app_id[64] = { 0 }; - memset(buffer, 0, sizeof(buffer)); - bleancs.getAttribute(notif->uid, ANCS_ATTR_APP_IDENTIFIER, buffer, sizeof(buffer)); - strcpy(app_id, buffer); - Serial.printf("%-20s | ", app_id); - - // Get Application Name - memset(buffer, 0, sizeof(buffer)); - bleancs.getAppAttribute(app_id, ANCS_APP_ATTR_DISPLAY_NAME, buffer, sizeof(buffer)); - Serial.printf("%-15s | ", buffer); + memset(buffer, 0, BUFSIZE); + bleancs.getMessage(uid, buffer, BUFSIZE); + Serial.printf(" %s\n", buffer); Serial.println(); diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/ancs_arcada/ancs_arcada.ino b/libraries/Bluefruit52Lib/examples/Peripheral/ancs_arcada/ancs_arcada.ino index f5abcd59e..aa47d2652 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/ancs_arcada/ancs_arcada.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/ancs_arcada/ancs_arcada.ino @@ -320,7 +320,7 @@ void ancs_notification_callback(AncsNotification_t* notif) // iDevice often include Unicode "Bidirection Text Control" in the Title. // Mostly are U+202D as beginning and U+202C as ending. Let's remove them - if ( bleancs.getTitle (uid, myNtf->title , BUFSIZE) ) + if ( bleancs.getTitle(uid, myNtf->title, BUFSIZE) ) { char u202D[3] = { 0xE2, 0x80, 0xAD }; // U+202D in UTF-8 char u202C[3] = { 0xE2, 0x80, 0xAC }; // U+202C in UTF-8 From b66cfc87a7d038429f43d9c91684e5cac7f72de0 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 18 Mar 2020 18:01:19 +0700 Subject: [PATCH 54/74] fix build for ancs oled --- .../Peripheral/ancs_arcada/ancs_arcada.ino | 17 +++-- .../Peripheral/ancs_oled/ancs_oled.ino | 64 ++++++++++++------- 2 files changed, 53 insertions(+), 28 deletions(-) diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/ancs_arcada/ancs_arcada.ino b/libraries/Bluefruit52Lib/examples/Peripheral/ancs_arcada/ancs_arcada.ino index aa47d2652..ff6ad5f2b 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/ancs_arcada/ancs_arcada.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/ancs_arcada/ancs_arcada.ino @@ -13,13 +13,18 @@ *********************************************************************/ /* - * This sketch is similar to 'ancs', but it also uses a Feather OLED - * Wing to display incoming ANCS alerts: - * https://www.adafruit.com/product/2900 + * This sketch is similar to 'ancs', but it uses TFT to display + * incoming ANCS alerts. Supported boards are: + * - CLUE https://www.adafruit.com/product/4500 + * - Circuit Playground Bluefruit + TFT Gizmo + * - https://www.adafruit.com/product/4333 + * - https://www.adafruit.com/product/4367 * - * BUTTON A: Up or accept call - * BUTTON B: Not used since it is hard to press - * BUTTON C: Down or decline call + * Button Left: Next or Answer call + * Button Right: Previous or Reject call + * + * Note on CPB button A is RIGHT and button B is LEFT, this is due to + * the TFT is on the back of the board. */ #include #include diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/ancs_oled/ancs_oled.ino b/libraries/Bluefruit52Lib/examples/Peripheral/ancs_oled/ancs_oled.ino index 07e0b5be7..49bf7208d 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/ancs_oled/ancs_oled.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/ancs_oled/ancs_oled.ino @@ -33,12 +33,6 @@ #define BUTTON_B 30 #define BUTTON_C 27 -#elif defined ARDUINO_NRF52840_CIRCUITPLAY - // Circuit Playground nRF52840 - FYI doesnt work probably because of button polarity! - #define BUTTON_A 4 // left button - #define BUTTON_B 7 // center switch - #define BUTTON_C 5 // right button - #else // Default for others #define BUTTON_A 9 @@ -67,7 +61,7 @@ MyNotif_t myNotifs[MAX_COUNT] = { 0 }; int notifCount = 0; /*------------- Display Management -------------*/ -#define ONSCREEN_TIME 5000 // On-screen time for each notification +#define ONSCREEN_TIME 10000 // On-screen time for each notification int activeIndex = 0; // Index of currently displayed notification int displayIndex = -1; // Index of notification about to display @@ -94,7 +88,7 @@ void setup() // Config the peripheral connection with maximum bandwidth // more SRAM required by SoftDevice // Note: All config***() function must be called before begin() - //Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); + Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); Bluefruit.begin(); Bluefruit.setTxPower(4); // Check bluefruit.h for supported values @@ -102,6 +96,9 @@ void setup() Bluefruit.Periph.setConnectCallback(connect_callback); Bluefruit.Periph.setDisconnectCallback(disconnect_callback); + // Set connection secured callback, invoked when connection is encrypted + Bluefruit.Pairing.setSecuredCallback(connection_secured_callback); + // Configure and Start Service bleancs.begin(); bleancs.setNotificationCallback(ancs_notification_callback); @@ -148,6 +145,13 @@ void startAdv(void) void loop() { + // This example only support 1 connection + uint16_t const conn_handle = 0; + BLEConnection* conn = Bluefruit.Connection(conn_handle); + + // connection exist, connected, and secured + if ( !(conn && conn->connected() && conn->secured()) ) return; + // If service is not yet discovered if ( !bleancs.discovered() ) return; @@ -261,6 +265,8 @@ void displayNotification(int index) */ void connect_callback(uint16_t conn_handle) { + BLEConnection* conn = Bluefruit.Connection(conn_handle); + oled.clearDisplay(); oled.setCursor(0, 0); oled.println("Connected."); @@ -272,20 +278,9 @@ void connect_callback(uint16_t conn_handle) oled.println("OK"); // ANCS requires pairing to work - oled.print("Paring ... "); - - oled.display(); - - if ( Bluefruit.requestPairing(conn_handle) ) - { - oled.println("OK"); - - bleancs.enableNotification(); - oled.println("Receiving ..."); - }else - { - oled.println("Failed"); - } + // request Pairing if not bonded + oled.println("Paring ... "); + conn->requestPairing(); }else { oled.println("Failed"); @@ -294,6 +289,31 @@ void connect_callback(uint16_t conn_handle) oled.display(); } +void connection_secured_callback(uint16_t conn_handle) +{ + BLEConnection* conn = Bluefruit.Connection(conn_handle); + + if ( !conn->secured() ) + { + // It is possible that connection is still not secured by this time. + // This happens (central only) when we try to encrypt connection using stored bond keys + // but peer reject it (probably it remove its stored key). + // Therefore we will request an pairing again --> callback again when encrypted + conn->requestPairing(); + } + else + { + Serial.println("Secured"); + + if ( bleancs.discovered() ) + { + bleancs.enableNotification(); + oled.println("Ready to receive"); + oled.display(); + } + } +} + /** * Notification callback * @param notif Notification from iDevice From a3beb000d7bcd4e6e6c71f3c8cc2f7e930b4b033 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 18 Mar 2020 22:20:13 +0700 Subject: [PATCH 55/74] fix build with client cts example --- .../Peripheral/client_cts/client_cts.ino | 49 ++++++++++++++----- .../client_cts_oled/client_cts_oled.ino | 49 ++++++++++++++----- 2 files changed, 76 insertions(+), 22 deletions(-) diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/client_cts/client_cts.ino b/libraries/Bluefruit52Lib/examples/Peripheral/client_cts/client_cts.ino index d354c81a7..e7507bcd2 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/client_cts/client_cts.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/client_cts/client_cts.ino @@ -33,7 +33,7 @@ BLEClientCts bleCTime; void setup() { Serial.begin(115200); - while ( !Serial ) delay(10); // for nrf52840 with native usb +// while ( !Serial ) delay(10); // for nrf52840 with native usb Serial.println("Bluefruit52 BLE Client Current Time Example"); Serial.println("-------------------------------------------\n"); @@ -48,10 +48,13 @@ void setup() Bluefruit.begin(); Bluefruit.setTxPower(4); // Check bluefruit.h for supported values - Bluefruit.setName("Bluefruit52"); + Bluefruit.Periph.setConnectCallback(connect_callback); Bluefruit.Periph.setDisconnectCallback(disconnect_callback); + // Set connection secured callback, invoked when connection is encrypted + Bluefruit.Pairing.setSecuredCallback(connection_secured_callback); + // Configure CTS client bleCTime.begin(); @@ -94,12 +97,16 @@ void startAdv(void) void loop() { + // This example only support 1 connection + uint16_t const conn_handle = 0; + BLEConnection* conn = Bluefruit.Connection(conn_handle); + + // connection exist, connected, and secured + if ( !(conn && conn->connected() && conn->secured()) ) return; + // Skip if service is not yet discovered if ( !bleCTime.discovered() ) return; - // Skip if service connection is not paired/secured - if ( !Bluefruit.connPaired( bleCTime.connHandle() ) ) return; - // Get Time from iOS once per second // Note it is not advised to update this quickly // Application should use local clock and update time after @@ -113,6 +120,8 @@ void loop() void connect_callback(uint16_t conn_handle) { + BLEConnection* conn = Bluefruit.Connection(conn_handle); + Serial.println("Connected"); Serial.print("Discovering CTS ... "); @@ -120,11 +129,31 @@ void connect_callback(uint16_t conn_handle) { Serial.println("Discovered"); - // iOS requires pairing to work, it makes sense to request security here as well - Serial.print("Attempting to PAIR with the iOS device, please press PAIR on your phone ... "); - if ( Bluefruit.requestPairing(conn_handle) ) + // Current Time Service requires pairing to work + // request Pairing if not bonded + Serial.println("Attempting to PAIR with the iOS device, please press PAIR on your phone ... "); + conn->requestPairing(); + } +} + +void connection_secured_callback(uint16_t conn_handle) +{ + BLEConnection* conn = Bluefruit.Connection(conn_handle); + + if ( !conn->secured() ) + { + // It is possible that connection is still not secured by this time. + // This happens (central only) when we try to encrypt connection using stored bond keys + // but peer reject it (probably it remove its stored key). + // Therefore we will request an pairing again --> callback again when encrypted + conn->requestPairing(); + } + else + { + Serial.println("Secured"); + + if ( bleCTime.discovered() ) { - Serial.println("Done"); Serial.println("Enabling Time Adjust Notify"); bleCTime.enableAdjust(); @@ -136,8 +165,6 @@ void connect_callback(uint16_t conn_handle) Serial.println(); } - - Serial.println(); } } diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/client_cts_oled/client_cts_oled.ino b/libraries/Bluefruit52Lib/examples/Peripheral/client_cts_oled/client_cts_oled.ino index 0372cf1b4..24657468c 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/client_cts_oled/client_cts_oled.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/client_cts_oled/client_cts_oled.ino @@ -54,10 +54,13 @@ void setup() Bluefruit.begin(); Bluefruit.setTxPower(4); // Check bluefruit.h for supported values - Bluefruit.setName("Bluefruit52"); + Bluefruit.Periph.setConnectCallback(connect_callback); Bluefruit.Periph.setDisconnectCallback(disconnect_callback); + // Set connection secured callback, invoked when connection is encrypted + Bluefruit.Pairing.setSecuredCallback(connection_secured_callback); + // Configure CTS client bleCTime.begin(); @@ -103,12 +106,16 @@ void startAdv(void) void loop() { + // This example only support 1 connection + uint16_t const conn_handle = 0; + BLEConnection* conn = Bluefruit.Connection(conn_handle); + + // connection exist, connected, and secured + if ( !(conn && conn->connected() && conn->secured()) ) return; + // Skip if service is not yet discovered if ( !bleCTime.discovered() ) return; - // Skip if service connection is not paired/secured - if ( !Bluefruit.connPaired( bleCTime.connHandle() ) ) return; - // Get Time from iOS once per second // Note it is not advised to update this quickly // Application should use local clock and update time after @@ -123,6 +130,8 @@ void loop() void connect_callback(uint16_t conn_handle) { + BLEConnection* conn = Bluefruit.Connection(conn_handle); + oled.clearDisplay(); oled.setCursor(0, 0); oled.println("Connected."); @@ -133,24 +142,42 @@ void connect_callback(uint16_t conn_handle) { oled.println("OK"); - // ANCS requires pairing to work + // Current Time Service requires pairing to work + // request Pairing if not bonded oled.print("Paring ... "); - oled.display(); - if ( Bluefruit.requestPairing(conn_handle) ) - { - oled.println("OK"); + conn->requestPairing(); + } +} +void connection_secured_callback(uint16_t conn_handle) +{ + BLEConnection* conn = Bluefruit.Connection(conn_handle); + + if ( !conn->secured() ) + { + // It is possible that connection is still not secured by this time. + // This happens (central only) when we try to encrypt connection using stored bond keys + // but peer reject it (probably it remove its stored key). + // Therefore we will request an pairing again --> callback again when encrypted + conn->requestPairing(); + } + else + { + oled.println("Secured"); + + if ( bleCTime.discovered() ) + { bleCTime.enableAdjust(); oled.println("Receiving Time..."); + oled.display(); + bleCTime.getCurrentTime(); bleCTime.getLocalTimeInfo(); } } - - oled.display(); } void printTime(void) From cc7de3d270b6b4ba062534caceffa4e34cd83046 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 18 Mar 2020 22:59:10 +0700 Subject: [PATCH 56/74] fix ancs_oled button --- cores/nRF5/Arduino.h | 4 ++-- .../examples/Peripheral/ancs_oled/ancs_oled.ino | 8 ++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/cores/nRF5/Arduino.h b/cores/nRF5/Arduino.h index 5497dbbd7..e4ab380ec 100644 --- a/cores/nRF5/Arduino.h +++ b/cores/nRF5/Arduino.h @@ -133,9 +133,9 @@ void suspendLoop(void); #define bit(b) (1UL << (b)) #ifdef NRF_P1 -#define digitalPinToPort(P) ( (g_ADigitalPinMap[P] < 32) ? NRF_P0 : NRF_P1 ) + #define digitalPinToPort(P) ( (g_ADigitalPinMap[P] < 32) ? NRF_P0 : NRF_P1 ) #else -#define digitalPinToPort(P) ( NRF_P0 ) + #define digitalPinToPort(P) ( NRF_P0 ) #endif #define digitalPinToBitMask(P) ( 1UL << ( g_ADigitalPinMap[P] < 32 ? g_ADigitalPinMap[P] : (g_ADigitalPinMap[P]-32) ) ) diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/ancs_oled/ancs_oled.ino b/libraries/Bluefruit52Lib/examples/Peripheral/ancs_oled/ancs_oled.ino index 49bf7208d..5b1a2958e 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/ancs_oled/ancs_oled.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/ancs_oled/ancs_oled.ino @@ -30,13 +30,11 @@ #if defined ARDUINO_NRF52832_FEATHER // Feather nRF52832 #define BUTTON_A 31 - #define BUTTON_B 30 #define BUTTON_C 27 #else // Default for others #define BUTTON_A 9 - #define BUTTON_B 6 #define BUTTON_C 5 #endif @@ -75,7 +73,6 @@ void setup() { // Button configured pinMode(BUTTON_A, INPUT_PULLUP); - pinMode(BUTTON_B, INPUT_PULLUP); pinMode(BUTTON_C, INPUT_PULLUP); // init with the I2C addr 0x3C (for the 128x32) and show splashscreen @@ -92,7 +89,7 @@ void setup() Bluefruit.begin(); Bluefruit.setTxPower(4); // Check bluefruit.h for supported values - Bluefruit.setName("Bluefruit52"); + Bluefruit.Periph.setConnectCallback(connect_callback); Bluefruit.Periph.setDisconnectCallback(disconnect_callback); @@ -453,8 +450,7 @@ uint32_t readPressedButtons(void) // Take current read and masked with BUTTONs // Note: Bitwise inverted since buttons are active (pressed) LOW - uint32_t debounced = ~(*portInputRegister( digitalPinToPort(0) )); - debounced &= (bit(BUTTON_A) | bit(BUTTON_B) | bit(BUTTON_C)); + uint32_t debounced = ~( (digitalRead(BUTTON_A) << BUTTON_A) | (digitalRead(BUTTON_C) << BUTTON_C) ); // Copy current state into array states[ (index & (MAX_CHECKS-1)) ] = debounced; From e0cda21a1aa08c4dcb510b5c9b367a7b6e8c65d5 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 18 Mar 2020 23:04:00 +0700 Subject: [PATCH 57/74] remove AdafruitBluefruit::requestPairing default CFG_DEFAULT_NAME to USB_PRODUCT --- .../Central/central_hid/central_hid.ino | 47 +++++++++++++------ libraries/Bluefruit52Lib/src/bluefruit.cpp | 17 ++----- libraries/Bluefruit52Lib/src/bluefruit.h | 3 +- 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/libraries/Bluefruit52Lib/examples/Central/central_hid/central_hid.ino b/libraries/Bluefruit52Lib/examples/Central/central_hid/central_hid.ino index 06a6d1e9d..2cf0da081 100644 --- a/libraries/Bluefruit52Lib/examples/Central/central_hid/central_hid.ino +++ b/libraries/Bluefruit52Lib/examples/Central/central_hid/central_hid.ino @@ -30,7 +30,7 @@ hid_mouse_report_t last_mse_report = { 0 }; void setup() { Serial.begin(115200); - while ( !Serial ) delay(10); // for nrf52840 with native usb +// while ( !Serial ) delay(10); // for nrf52840 with native usb Serial.println("Bluefruit52 Central HID (Keyboard + Mouse) Example"); Serial.println("--------------------------------------------------\n"); @@ -55,6 +55,9 @@ void setup() Bluefruit.Central.setConnectCallback(connect_callback); Bluefruit.Central.setDisconnectCallback(disconnect_callback); + // Set connection secured callback, invoked when connection is encrypted + Bluefruit.Pairing.setSecuredCallback(connection_secured_callback); + /* Start Central Scanning * - Enable auto scan if disconnected * - Interval = 100 ms, window = 80 ms @@ -88,6 +91,8 @@ void scan_callback(ble_gap_evt_adv_report_t* report) */ void connect_callback(uint16_t conn_handle) { + BLEConnection* conn = Bluefruit.Connection(conn_handle); + Serial.println("Connected"); Serial.print("Discovering HID Service ... "); @@ -97,11 +102,31 @@ void connect_callback(uint16_t conn_handle) Serial.println("Found it"); // HID device mostly require pairing/bonding - if ( !Bluefruit.requestPairing(conn_handle) ) - { - Serial.print("Failed to paired"); - return; - } + conn->requestPairing(); + }else + { + Serial.println("Found NONE"); + + // disconnect since we couldn't find blehid service + conn->disconnect(); + } +} + +void connection_secured_callback(uint16_t conn_handle) +{ + BLEConnection* conn = Bluefruit.Connection(conn_handle); + + if ( !conn->secured() ) + { + // It is possible that connection is still not secured by this time. + // This happens (central only) when we try to encrypt connection using stored bond keys + // but peer reject it (probably it remove its stored key). + // Therefore we will request an pairing again --> callback again when encrypted + conn->requestPairing(); + } + else + { + Serial.println("Secured"); // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.hid_information.xml uint8_t hidInfo[4]; @@ -120,15 +145,9 @@ void connect_callback(uint16_t conn_handle) // Enable Mouse report notification if present on prph if ( hid.mousePresent() ) hid.enableMouse(); - + Serial.println("Ready to receive from peripheral"); - }else - { - Serial.println("Found NONE"); - - // disconnect since we couldn't find blehid service - Bluefruit.disconnect(conn_handle); - } + } } /** diff --git a/libraries/Bluefruit52Lib/src/bluefruit.cpp b/libraries/Bluefruit52Lib/src/bluefruit.cpp index 9fe0b6f6b..b15c76879 100644 --- a/libraries/Bluefruit52Lib/src/bluefruit.cpp +++ b/libraries/Bluefruit52Lib/src/bluefruit.cpp @@ -41,8 +41,10 @@ #define CFG_BLE_TX_POWER_LEVEL 0 #endif -#ifndef CFG_DEFAULT_NAME -#define CFG_DEFAULT_NAME "Bluefruit52" +#ifdef USB_PRODUCT + #define CFG_DEFAULT_NAME USB_PRODUCT +#else + #define CFG_DEFAULT_NAME "Feather nRF52832" #endif #ifndef CFG_BLE_TASK_STACKSIZE @@ -916,17 +918,6 @@ void AdafruitBluefruit::_setConnLed (bool on_off) } } -/*------------------------------------------------------------------*/ -/* Bonds - *------------------------------------------------------------------*/ -bool AdafruitBluefruit::requestPairing(uint16_t conn_hdl) -{ - BLEConnection* conn = this->Connection(conn_hdl); - VERIFY(conn); - - return conn->requestPairing(); -} - //--------------------------------------------------------------------+ // //--------------------------------------------------------------------+ diff --git a/libraries/Bluefruit52Lib/src/bluefruit.h b/libraries/Bluefruit52Lib/src/bluefruit.h index c58f6bcba..5afa0bd2b 100644 --- a/libraries/Bluefruit52Lib/src/bluefruit.h +++ b/libraries/Bluefruit52Lib/src/bluefruit.h @@ -164,11 +164,10 @@ class AdafruitBluefruit bool connected (uint16_t conn_hdl); uint16_t connHandle (void); - bool connPaired (uint16_t conn_hdl); // Alias to BLEConnection API() + bool connPaired (uint16_t conn_hdl); bool disconnect (uint16_t conn_hdl); - bool requestPairing (uint16_t conn_hdl); uint16_t getMaxMtu(uint8_t role); From 3615893872ed496f74d38f481570667a8d3272b3 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 19 Mar 2020 10:54:41 +0700 Subject: [PATCH 58/74] rename pairing_display to pairing_passkey --- .../pairing_passkey.ino} | 190 ++++++------------ 1 file changed, 61 insertions(+), 129 deletions(-) rename libraries/Bluefruit52Lib/examples/Peripheral/{pairing_display/pairing_display.ino => pairing_passkey/pairing_passkey.ino} (68%) diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino similarity index 68% rename from libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino rename to libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino index 0c105ef31..b63fb5428 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_display/pairing_display.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino @@ -12,6 +12,17 @@ any redistribution *********************************************************************/ +#if defined(ARDUINO_NRF52840_CIRCUITPLAY) || defined(ARDUINO_NRF52840_CLUE) + #define USE_ARCADA +#endif + +#ifdef USE_ARCADA +#include + +Adafruit_Arcada arcada; +Adafruit_SPITFT* tft; +#endif + #include #include #include @@ -33,68 +44,11 @@ /* This sketch demonstrates the "Image Upload" feature of Bluefruit Mobile App. * Following TFT Display are supported - * - TFT 3.5" : FeatherWing https://www.adafruit.com/product/3651 - * - TFT 2.4" : FeatherWing https://www.adafruit.com/product/3315 + * - Circuit Playground Bluefruit: https://www.adafruit.com/product/4333 * - TFT Gizmo : https://www.adafruit.com/product/4367 * - Adafruit CLUE : https://www.adafruit.com/product/4500 */ -#define TFT_NO_DISPLAY 0 -#define TFT_GIZMO 1 // used with Circuit Playground Bluefruit -#define TFT_CLUE 2 // CLUE's on-board display -#define TFT_24_FEATHERWING 3 -#define TFT_35_FEATHERWING 4 - - -#if defined(ARDUINO_NRF52840_CIRCUITPLAY) - // Circuit Playground Bluefruit use with TFT GIZMO - #define TFT_IN_USE TFT_GIZMO - #define DEVICE_NAME "CPLAY" - - #include "Adafruit_ST7789.h" - Adafruit_ST7789 tft = Adafruit_ST7789(&SPI, 0, 1, -1); // CS = 0, DC = 1 - -#elif defined(ARDUINO_NRF52840_CLUE) - // CLUE use on-board TFT - #define TFT_IN_USE TFT_CLUE - #define DEVICE_NAME "CLUE" - - #include "Adafruit_ST7789.h" - Adafruit_ST7789 tft = Adafruit_ST7789(&SPI1, PIN_TFT_CS, PIN_TFT_DC, PIN_TFT_RST); - -#else - // [Configurable] For other boards please select which external display to match your hardware setup - #define TFT_IN_USE TFT_24_FEATHERWING - #define DEVICE_NAME "Feather" - - #if defined(ARDUINO_NRF52832_FEATHER) - // Feather nRF52832 pin map is different from others - #define TFT_DC 11 - #define TFT_CS 31 - #else - // Default for others - #define TFT_DC 10 - #define TFT_CS 9 - #endif - - #if TFT_IN_USE == TFT_35_FEATHERWING - #include "Adafruit_HX8357.h" - Adafruit_HX8357 tft = Adafruit_HX8357(TFT_CS, TFT_DC); - - #elif TFT_IN_USE == TFT_24_FEATHERWING - #include - Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); - #endif // TFT - -#endif // board variants - - -#define COLOR_WHITE 0xFFFF -#define COLOR_BLACK 0x0000 -#define COLOR_YELLOW 0xFFE0 -#define COLOR_GREEN 0x07E0 -#define COLOR_RED 0xF800 - // BLE Service BLEUart bleuart; // uart over ble @@ -105,35 +59,14 @@ void setup() Serial.println("Bluefruit52 Pairing Display Example"); Serial.println("-----------------------------------\n"); -#if TFT_IN_USE == TFT_CLUE - tft.init(240, 240); - tft.setRotation(1); - - // Screen refresh rate control (datasheet 9.2.18, FRCTRL2) - uint8_t rtna = 0x01; - tft.sendCommand(0xC6, &rtna, 1);; - - // turn back light on - uint8_t backlight = PIN_TFT_LITE; - pinMode(backlight, OUTPUT); - digitalWrite(backlight, HIGH); - -#elif TFT_IN_USE == TFT_GIZMO - tft.init(240, 240); - tft.setRotation(2); - - // turn back light on - uint8_t backlight = A3; - pinMode(backlight, OUTPUT); - digitalWrite(backlight, HIGH); - -#elif TFT_IN_USE != TFT_NO_DISPLAY - tft.begin(); - -#endif // TFT + arcada.arcadaBegin(); + arcada.displayBegin(); + arcada.setBacklight(255); - pinMode(PIN_BUTTON1, INPUT_PULLUP); - pinMode(PIN_BUTTON2, INPUT_PULLUP); + tft = arcada.display; + tft->setCursor(0, 0); + tft->setTextWrap(true); + tft->setTextSize(2); // Setup the BLE LED to be enabled on CONNECT // Note: This is actually the default behavior, but provided @@ -147,7 +80,6 @@ void setup() Bluefruit.begin(); Bluefruit.setTxPower(4); // Check bluefruit.h for supported values - Bluefruit.setName(DEVICE_NAME); // clear bonds if BUTTON A is pressed Serial.println("Hold button A to clear bonds ..... "); @@ -182,12 +114,12 @@ void setup() bleuart.setPermission(SECMODE_ENC_WITH_MITM); bleuart.begin(); -#if TFT_IN_USE != TFT_NO_DISPLAY - tft.fillScreen(COLOR_BLACK); - tft.setTextColor(COLOR_WHITE); - tft.setTextSize(2); - tft.setCursor(0, 0); - tft.print("Advertising..."); +#ifdef USE_ARCADA + tft->fillScreen(ARCADA_BLACK); + tft->setTextColor(ARCADA_WHITE); + tft->setTextSize(2); + tft->setCursor(0, 0); + tft->print("Advertising..."); #endif Serial.println("Please use Adafruit's Bluefruit LE app to connect in UART mode"); @@ -261,11 +193,11 @@ void connect_callback(uint16_t conn_handle) Serial.print("Connected to "); Serial.println(central_name); -#if TFT_IN_USE != TFT_NO_DISPLAY - tft.fillScreen(COLOR_BLACK); - tft.setTextSize(2); - tft.setCursor(0, 0); - tft.println("Connected"); +#ifdef USE_ARCADA + tft->fillScreen(ARCADA_BLACK); + tft->setTextSize(2); + tft->setCursor(0, 0); + tft->println("Connected"); #endif } @@ -279,15 +211,15 @@ bool pairing_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6], bo Serial.println("Pairing Passkey"); Serial.printf(" %.3s %.3s\n", passkey, passkey+3); -#if TFT_IN_USE != TFT_NO_DISPLAY - tft.fillScreen(COLOR_BLACK); - tft.println("Pairing Passkey\n"); - tft.setTextColor(COLOR_YELLOW); - tft.setTextSize(4); - tft.printf(" %.3s %.3s\n", passkey, passkey+3); +#ifdef USE_ARCADA + tft->fillScreen(ARCADA_BLACK); + tft->println("Pairing Passkey\n"); + tft->setTextColor(ARCADA_YELLOW); + tft->setTextSize(4); + tft->printf(" %.3s %.3s\n", passkey, passkey+3); - tft.setTextColor(COLOR_WHITE); - tft.setTextSize(2); + tft->setTextColor(ARCADA_WHITE); + tft->setTextSize(2); #endif @@ -296,18 +228,18 @@ bool pairing_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6], bo Serial.println("Do you want to pair"); Serial.println("Press Button A to accept, Button B to reject"); - #if TFT_IN_USE != TFT_NO_DISPLAY - tft.println("\nDo you accept ?\n\n"); + #ifdef USE_ARCADA + tft->println("\nDo you accept ?\n\n"); - tft.setTextSize(3); - tft.setTextColor(COLOR_GREEN); - tft.print("<< Yes"); - tft.setTextColor(COLOR_RED); - tft.println(" No >>"); + tft->setTextSize(3); + tft->setTextColor(ARCADA_GREEN); + tft->print("<< Yes"); + tft->setTextColor(ARCADA_RED); + tft->println(" No >>"); - tft.setTextColor(COLOR_WHITE); - tft.setTextSize(2); - tft.println(); + tft->setTextColor(ARCADA_WHITE); + tft->setTextSize(2); + tft->println(); #endif // wait until either button is pressed @@ -343,19 +275,19 @@ void pairing_complete_callback(uint16_t conn_handle, uint8_t auth_status) Serial.println("Failed"); } - #if TFT_IN_USE != TFT_NO_DISPLAY + #ifdef USE_ARCADA if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS) { - tft.setTextColor(COLOR_GREEN); - tft.println("Succeeded"); + tft->setTextColor(ARCADA_GREEN); + tft->println("Succeeded"); }else { - tft.setTextColor(COLOR_RED); - tft.println("Failed"); + tft->setTextColor(ARCADA_RED); + tft->println("Failed"); } - tft.setTextColor(COLOR_WHITE); - tft.setTextSize(2); + tft->setTextColor(ARCADA_WHITE); + tft->setTextSize(2); #endif } @@ -363,10 +295,10 @@ void connection_secured_callback(uint16_t conn_handle) { Serial.println("Secured"); - #if TFT_IN_USE != TFT_NO_DISPLAY - tft.setTextColor(COLOR_YELLOW); - tft.println("secured"); - tft.setTextColor(COLOR_WHITE); + #ifdef USE_ARCADA + tft->setTextColor(ARCADA_YELLOW); + tft->println("secured"); + tft->setTextColor(ARCADA_WHITE); #endif } @@ -383,7 +315,7 @@ void disconnect_callback(uint16_t conn_handle, uint8_t reason) Serial.println(); Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX); -#if TFT_IN_USE != TFT_NO_DISPLAY - tft.println("Advertising ..."); +#ifdef USE_ARCADA + tft->println("Advertising ..."); #endif } From d65525f20dcd7d0e3204d0d29d97b2c2c3a27106 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 19 Mar 2020 12:21:41 +0700 Subject: [PATCH 59/74] use arcada for pairing passkey --- .../pairing_passkey/pairing_passkey.ino | 133 ++++++++++++------ 1 file changed, 88 insertions(+), 45 deletions(-) diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino index b63fb5428..1db9874b3 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino @@ -16,20 +16,33 @@ #define USE_ARCADA #endif -#ifdef USE_ARCADA -#include - -Adafruit_Arcada arcada; -Adafruit_SPITFT* tft; -#endif - -#include -#include #include #include #include #include +#ifdef USE_ARCADA + #include + + Adafruit_Arcada arcada; + Adafruit_SPITFT* tft; + +#else + // Use built-in buttons if available, else use A0, A1 + #ifdef PIN_BUTTON1 + #define BUTTON_YES PIN_BUTTON1 + #else + #define BUTTON_YES A0 + #endif + + #ifdef PIN_BUTTON2 + #define BUTTON_NO PIN_BUTTON2 + #else + #define BUTTON_NO A1 + #endif +#endif + + /* This sketch demonstrates Pairing process using dynamic Passkey. * This sketch is essentially the same as bleuart.ino except the BLE Uart * service requires Security Mode with Man-In-The-Middle protection i.e @@ -59,6 +72,7 @@ void setup() Serial.println("Bluefruit52 Pairing Display Example"); Serial.println("-----------------------------------\n"); +#ifdef USE_ARCADA arcada.arcadaBegin(); arcada.displayBegin(); arcada.setBacklight(255); @@ -67,6 +81,10 @@ void setup() tft->setCursor(0, 0); tft->setTextWrap(true); tft->setTextSize(2); +#else + pinMode(BUTTON_YES, INPUT_PULLUP); + pinMode(BUTTON_NO, INPUT_PULLUP); +#endif // Setup the BLE LED to be enabled on CONNECT // Note: This is actually the default behavior, but provided @@ -82,19 +100,23 @@ void setup() Bluefruit.setTxPower(4); // Check bluefruit.h for supported values // clear bonds if BUTTON A is pressed - Serial.println("Hold button A to clear bonds ..... "); - delay(2000); - if (0 == digitalRead(PIN_BUTTON1)) - { - Serial.println("Clear all central bonds"); - Bluefruit.Periph.clearBonds(); - } - - // To use dynamic PassKey for pairing, we need to have - // - IO capacities at least DISPPLAY - // - Register callback to display/print dynamic passkey for central - // For complete mapping of the IO Capabilities to Key Generation Method, check out this article - // https://www.bluetooth.com/blog/bluetooth-pairing-part-2-key-generation-methods/ +// Serial.println("Hold button A to clear bonds ..... "); +// delay(2000); +// if (0 == digitalRead(PIN_BUTTON1)) +// { +// Serial.println("Clear all central bonds"); +// Bluefruit.Periph.clearBonds(); +// } + + /* To use dynamic PassKey for pairing, we need to have + * - IO capacities at least DISPPLAY + * - Display only: user have to enter 6-digit passkey on their phone + * - DIsplay + Yes/No: user ony need to press Accept on both central and device + * - Register callback to display/print dynamic passkey for central + * + * For complete mapping of the IO Capabilities to Key Generation Method, check out this article + * https://www.bluetooth.com/blog/bluetooth-pairing-part-2-key-generation-methods/ + */ Bluefruit.Pairing.setIOCaps(true, true, false); // display = true, yes/no = true, keyboard = false Bluefruit.Pairing.setPasskeyCallback(pairing_passkey_callback); @@ -222,42 +244,63 @@ bool pairing_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6], bo tft->setTextSize(2); #endif - + // match_request means peer wait for our approval (return true) if (match_request) { Serial.println("Do you want to pair"); - Serial.println("Press Button A to accept, Button B to reject"); + Serial.println("Press Button Left to decline, Button Right to Accept"); - #ifdef USE_ARCADA - tft->println("\nDo you accept ?\n\n"); + // timeout for pressing button + uint32_t start_time = millis(); +#ifdef USE_ARCADA + tft->println("\nDo you accept ?\n\n"); tft->setTextSize(3); - tft->setTextColor(ARCADA_GREEN); - tft->print("<< Yes"); - tft->setTextColor(ARCADA_RED); - tft->println(" No >>"); + + // Yes <-> No on CPB is reversed since GIZMO TFT is on the back of CPB + #if ARDUINO_NRF52840_CIRCUITPLAY + tft->setTextColor(ARCADA_GREEN); + tft->print("< Yes"); + tft->setTextColor(ARCADA_RED); + tft->println(" No >"); + #else + tft->setTextColor(ARCADA_RED); + tft->print("< No"); + tft->setTextColor(ARCADA_GREEN); + tft->println(" Yes >"); + #endif tft->setTextColor(ARCADA_WHITE); tft->setTextSize(2); tft->println(); - #endif - // wait until either button is pressed - while( digitalRead(PIN_BUTTON1) && digitalRead(PIN_BUTTON2) ) { } + // wait until either button is pressed (30 seconds timeout) + uint32_t justReleased; + do + { + if ( millis() > start_time + 30000 ) break; - // wait until either button is pressed - uint32_t start_time = millis(); - while( digitalRead(PIN_BUTTON1) && digitalRead(PIN_BUTTON2) ) + arcada.readButtons(); + justReleased = arcada.justReleasedButtons(); + } while ( !(justReleased & (ARCADA_BUTTONMASK_LEFT | ARCADA_BUTTONMASK_RIGHT) ) ); + + // Right = accept + if (justReleased & ARCADA_BUTTONMASK_RIGHT) return true; + + // Left = decline + if (justReleased & ARCADA_BUTTONMASK_LEFT) return false; + +#else + // wait until either button is pressed (30 seconds timeout) + while( digitalRead(BUTTON_YES) && digitalRead(BUTTON_NO) ) { - // 30 seconds timeout if ( millis() > start_time + 30000 ) break; } - // A = accept - if ( 0 == digitalRead(PIN_BUTTON1) ) return true; + if ( 0 == digitalRead(BUTTON_YES) ) return true; - // B = reject - if ( 0 == digitalRead(PIN_BUTTON2) ) return false; + if ( 0 == digitalRead(BUTTON_NO) ) return false; +#endif return false; } @@ -275,7 +318,7 @@ void pairing_complete_callback(uint16_t conn_handle, uint8_t auth_status) Serial.println("Failed"); } - #ifdef USE_ARCADA +#ifdef USE_ARCADA if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS) { tft->setTextColor(ARCADA_GREEN); @@ -288,18 +331,18 @@ void pairing_complete_callback(uint16_t conn_handle, uint8_t auth_status) tft->setTextColor(ARCADA_WHITE); tft->setTextSize(2); - #endif +#endif } void connection_secured_callback(uint16_t conn_handle) { Serial.println("Secured"); - #ifdef USE_ARCADA +#ifdef USE_ARCADA tft->setTextColor(ARCADA_YELLOW); tft->println("secured"); tft->setTextColor(ARCADA_WHITE); - #endif +#endif } /** From 34718f8d98fe25aed52a8b7c6af5285b7e2bf70e Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 19 Mar 2020 14:46:57 +0700 Subject: [PATCH 60/74] update central pairing with acarda --- .../central_pairing/central_pairing.ino | 260 +++++++++--------- .../pairing_passkey/pairing_passkey.ino | 55 ++-- 2 files changed, 153 insertions(+), 162 deletions(-) diff --git a/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino b/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino index 931e478ff..673856a94 100644 --- a/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino +++ b/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino @@ -15,7 +15,7 @@ #include /* This sketch demonstrates Pairing process using dynamic Passkey. - * This sketch is essentially the same as bleuart.ino except the BLE Uart + * This sketch is essentially the same as central_bleuart.ino except the BLE Uart * service requires Security Mode with Man-In-The-Middle protection i.e * * BLE Pairing procedure is complicated, it is advisable for users to go through @@ -24,63 +24,43 @@ * - https://www.bluetooth.com/blog/bluetooth-pairing-part-2-key-generation-methods/ * - https://www.bluetooth.com/blog/bluetooth-pairing-passkey-entry/ * - https://www.bluetooth.com/blog/bluetooth-pairing-part-4/ + * + * IF TFT enabled board such as CLUE is used, the passkey will also display on the + * tft-> Following boards with TFT are supported + * - Adafruit CLUE : https://www.adafruit.com/product/4500 + * - Circuit Playground Bluefruit: https://www.adafruit.com/product/4333 + * - TFT Gizmo : https://www.adafruit.com/product/4367 */ -#define TFT_NO_DISPLAY 0 -#define TFT_GIZMO 1 // used with Circuit Playground Bluefruit -#define TFT_CLUE 2 // CLUE's on-board display -#define TFT_24_FEATHERWING 3 -#define TFT_35_FEATHERWING 4 - - -#if defined(ARDUINO_NRF52840_CIRCUITPLAY) - // Circuit Playground Bluefruit use with TFT GIZMO - #define TFT_IN_USE TFT_GIZMO - #define DEVICE_NAME "CPLAY" +#if defined(ARDUINO_NRF52840_CIRCUITPLAY) || defined(ARDUINO_NRF52840_CLUE) + #define USE_ARCADA +#endif - #include "Adafruit_ST7789.h" - Adafruit_ST7789 tft = Adafruit_ST7789(&SPI, 0, 1, -1); // CS = 0, DC = 1 +#include +#include +#include +#include -#elif defined(ARDUINO_NRF52840_CLUE) - // CLUE use on-board TFT - #define TFT_IN_USE TFT_CLUE - #define DEVICE_NAME "CLUE" +#ifdef USE_ARCADA + #include - #include "Adafruit_ST7789.h" - Adafruit_ST7789 tft = Adafruit_ST7789(&SPI1, PIN_TFT_CS, PIN_TFT_DC, PIN_TFT_RST); + Adafruit_Arcada arcada; + Adafruit_SPITFT* tft; #else - // [Configurable] For other boards please select which external display to match your hardware setup - #define TFT_IN_USE TFT_24_FEATHERWING - #define DEVICE_NAME "Feather" - - #if defined(ARDUINO_NRF52832_FEATHER) - // Feather nRF52832 pin map is different from others - #define TFT_DC 11 - #define TFT_CS 31 + // Use built-in buttons if available, else use A0, A1 + #ifdef PIN_BUTTON1 + #define BUTTON_YES PIN_BUTTON1 #else - // Default for others - #define TFT_DC 10 - #define TFT_CS 9 + #define BUTTON_YES A0 #endif - #if TFT_IN_USE == TFT_35_FEATHERWING - #include "Adafruit_HX8357.h" - Adafruit_HX8357 tft = Adafruit_HX8357(TFT_CS, TFT_DC); - - #elif TFT_IN_USE == TFT_24_FEATHERWING - #include - Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); - #endif // TFT - -#endif // board variants - - -#define COLOR_WHITE 0xFFFF -#define COLOR_BLACK 0x0000 -#define COLOR_YELLOW 0xFFE0 -#define COLOR_GREEN 0x07E0 -#define COLOR_RED 0xF800 + #ifdef PIN_BUTTON2 + #define BUTTON_NO PIN_BUTTON2 + #else + #define BUTTON_NO A1 + #endif +#endif BLEClientUart clientUart; // bleuart client @@ -91,43 +71,27 @@ void setup() Serial.println("Bluefruit52 Central Pairing Example"); Serial.println("-----------------------------------\n"); -#if TFT_IN_USE == TFT_CLUE - tft.init(240, 240); - tft.setRotation(1); - - // Screen refresh rate control (datasheet 9.2.18, FRCTRL2) - uint8_t rtna = 0x01; - tft.sendCommand(0xC6, &rtna, 1);; - - // turn back light on - uint8_t backlight = PIN_TFT_LITE; - pinMode(backlight, OUTPUT); - digitalWrite(backlight, HIGH); - -#elif TFT_IN_USE == TFT_GIZMO - tft.init(240, 240); - tft.setRotation(2); - - // turn back light on - uint8_t backlight = A3; - pinMode(backlight, OUTPUT); - digitalWrite(backlight, HIGH); - -#elif TFT_IN_USE != TFT_NO_DISPLAY - tft.begin(); - -#endif // TFT - - pinMode(PIN_BUTTON1, INPUT_PULLUP); - pinMode(PIN_BUTTON2, INPUT_PULLUP); +#ifdef USE_ARCADA + arcada.arcadaBegin(); + arcada.displayBegin(); + arcada.setBacklight(255); + + tft = arcada.display; + tft->setCursor(0, 0); + tft->setTextWrap(true); + tft->setTextSize(2); +#else + pinMode(BUTTON_YES, INPUT_PULLUP); + pinMode(BUTTON_NO, INPUT_PULLUP); +#endif // Initialize Bluefruit with maximum connections as Peripheral = 0, Central = 1 // SRAM usage required by SoftDevice will increase dramatically with number of connections Bluefruit.begin(0, 1); - Bluefruit.setName("Bluefruit52 Central"); - + // clear bonds if BUTTON A is pressed Serial.println("Hold button A to clear bonds ..... "); + Serial.flush(); delay(2000); if (0 == digitalRead(PIN_BUTTON1)) { @@ -160,12 +124,12 @@ void setup() Bluefruit.Central.setConnectCallback(connect_callback); Bluefruit.Central.setDisconnectCallback(disconnect_callback); -#if TFT_IN_USE != TFT_NO_DISPLAY - tft.fillScreen(COLOR_BLACK); - tft.setTextColor(COLOR_WHITE); - tft.setTextSize(2); - tft.setCursor(0, 0); - tft.println("Scanning ..."); +#ifdef USE_ARCADA + tft->fillScreen(ARCADA_BLACK); + tft->setTextColor(ARCADA_WHITE); + tft->setTextSize(2); + tft->setCursor(0, 0); + tft->println("Scanning ..."); #endif /* Start Central Scanning @@ -212,11 +176,11 @@ void connect_callback(uint16_t conn_handle) Serial.println("Connected"); -#if TFT_IN_USE != TFT_NO_DISPLAY - tft.fillScreen(COLOR_BLACK); - tft.setTextSize(2); - tft.setCursor(0, 0); - tft.println("Connected"); +#ifdef USE_ARCADA + tft->fillScreen(ARCADA_BLACK); + tft->setTextSize(2); + tft->setCursor(0, 0); + tft->println("Connected"); #endif // If we are not bonded with peer previously -> send pairing request @@ -239,8 +203,8 @@ void disconnect_callback(uint16_t conn_handle, uint8_t reason) Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX); -#if TFT_IN_USE != TFT_NO_DISPLAY - tft.println("Scanning ..."); +#ifdef USE_ARCADA + tft->println("Scanning ..."); #endif } @@ -262,49 +226,74 @@ bool pairing_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6], bo Serial.println("Pairing Passkey"); Serial.printf(" %.3s %.3s\n\n", passkey, passkey+3); -#if TFT_IN_USE != TFT_NO_DISPLAY - tft.fillScreen(COLOR_BLACK); - tft.println("Pairing Passkey\n"); - tft.setTextColor(COLOR_YELLOW); - tft.setTextSize(4); - tft.printf(" %.3s %.3s\n", passkey, passkey+3); +#ifdef USE_ARCADA + tft->fillScreen(ARCADA_BLACK); + tft->println("Pairing Passkey\n"); + tft->setTextColor(ARCADA_YELLOW); + tft->setTextSize(4); + tft->printf(" %.3s %.3s\n", passkey, passkey+3); - tft.setTextColor(COLOR_WHITE); - tft.setTextSize(2); + tft->setTextColor(ARCADA_WHITE); + tft->setTextSize(2); #endif + // match_request means peer wait for our approval (return true) if (match_request) { - Serial.println("Do you want to pair ?"); - Serial.println("Press Button A to accept, Button B to reject"); - - #if TFT_IN_USE != TFT_NO_DISPLAY - tft.println("\nDo you accept ?\n\n"); + Serial.println("Do you want to pair"); + Serial.println("Press Button Left to decline, Button Right to Accept"); - tft.setTextSize(3); - tft.setTextColor(COLOR_GREEN); - tft.print("<< Yes"); - tft.setTextColor(COLOR_RED); - tft.println(" No >>"); + // timeout for pressing button + uint32_t start_time = millis(); - tft.setTextColor(COLOR_WHITE); - tft.setTextSize(2); - tft.println(); +#ifdef USE_ARCADA + tft->println("\nDo you accept ?\n\n"); + tft->setTextSize(3); + + // Yes <-> No on CPB is reversed since GIZMO TFT is on the back of CPB + #if ARDUINO_NRF52840_CIRCUITPLAY + tft->setTextColor(ARCADA_GREEN); + tft->print("< Yes"); + tft->setTextColor(ARCADA_RED); + tft->println(" No >"); + #else + tft->setTextColor(ARCADA_RED); + tft->print("< No"); + tft->setTextColor(ARCADA_GREEN); + tft->println(" Yes >"); #endif - // wait until either button is pressed - uint32_t start_time = millis(); - while( digitalRead(PIN_BUTTON1) && digitalRead(PIN_BUTTON2) ) + tft->setTextColor(ARCADA_WHITE); + tft->setTextSize(2); + tft->println(); + + // wait until either button is pressed (30 seconds timeout) + uint32_t justReleased; + do + { + if ( millis() > start_time + 30000 ) break; + + arcada.readButtons(); + justReleased = arcada.justReleasedButtons(); + } while ( !(justReleased & (ARCADA_BUTTONMASK_LEFT | ARCADA_BUTTONMASK_RIGHT) ) ); + + // Right = accept + if (justReleased & ARCADA_BUTTONMASK_RIGHT) return true; + + // Left = decline + if (justReleased & ARCADA_BUTTONMASK_LEFT) return false; + +#else + // wait until either button is pressed (30 seconds timeout) + while( digitalRead(BUTTON_YES) && digitalRead(BUTTON_NO) ) { - // 30 seconds timeout if ( millis() > start_time + 30000 ) break; } - // A = accept - if ( 0 == digitalRead(PIN_BUTTON1) ) return true; + if ( 0 == digitalRead(BUTTON_YES) ) return true; - // B = reject - if ( 0 == digitalRead(PIN_BUTTON2) ) return false; + if ( 0 == digitalRead(BUTTON_NO) ) return false; +#endif return false; } @@ -314,6 +303,8 @@ bool pairing_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6], bo void pairing_complete_callback(uint16_t conn_handle, uint8_t auth_status) { + BLEConnection* conn = Bluefruit.Connection(conn_handle); + if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS) { Serial.println("Succeeded"); @@ -322,19 +313,22 @@ void pairing_complete_callback(uint16_t conn_handle, uint8_t auth_status) Serial.println("Failed"); } -#if TFT_IN_USE != TFT_NO_DISPLAY +#ifdef USE_ARCADA if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS) { - tft.setTextColor(COLOR_GREEN); - tft.print("Succeeded "); + tft->setTextColor(ARCADA_GREEN); + tft->print("Succeeded "); }else { - tft.setTextColor(COLOR_RED); - tft.print("Failed "); + tft->setTextColor(ARCADA_RED); + tft->print("Failed "); + + // disconnect + conn->disconnect(); } - tft.setTextColor(COLOR_WHITE); - tft.setTextSize(2); + tft->setTextColor(ARCADA_WHITE); + tft->setTextSize(2); #endif } @@ -354,10 +348,10 @@ void connection_secured_callback(uint16_t conn_handle) { Serial.println("Secured"); - #if TFT_IN_USE != TFT_NO_DISPLAY - tft.setTextColor(COLOR_YELLOW); - tft.println("secured"); - tft.setTextColor(COLOR_WHITE); + #ifdef USE_ARCADA + tft->setTextColor(ARCADA_YELLOW); + tft->println("secured"); + tft->setTextColor(ARCADA_WHITE); #endif Serial.print("Discovering BLE Uart Service ... "); @@ -374,7 +368,7 @@ void connection_secured_callback(uint16_t conn_handle) Serial.println("Found NONE"); // disconnect since we couldn't find bleuart service - Bluefruit.disconnect(conn_handle); + conn->disconnect(); } } } diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino index 1db9874b3..e064f8fa0 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino @@ -12,6 +12,24 @@ any redistribution *********************************************************************/ +/* This sketch demonstrates Pairing process using dynamic Passkey. + * This sketch is essentially the same as bleuart.ino except the BLE Uart + * service requires Security Mode with Man-In-The-Middle protection i.e + * + * BLE Pairing procedure is complicated, it is advisable for users to go through + * these articles to get familiar with the procedure and terminology + * - https://www.bluetooth.com/blog/bluetooth-pairing-part-1-pairing-feature-exchange/ + * - https://www.bluetooth.com/blog/bluetooth-pairing-part-2-key-generation-methods/ + * - https://www.bluetooth.com/blog/bluetooth-pairing-passkey-entry/ + * - https://www.bluetooth.com/blog/bluetooth-pairing-part-4/ + * + * IF TFT enabled board such as CLUE is used, the passkey will also display on the + * TFT. Following boards with TFT are supported + * - Adafruit CLUE : https://www.adafruit.com/product/4500 + * - Circuit Playground Bluefruit: https://www.adafruit.com/product/4333 + * - TFT Gizmo : https://www.adafruit.com/product/4367 + */ + #if defined(ARDUINO_NRF52840_CIRCUITPLAY) || defined(ARDUINO_NRF52840_CLUE) #define USE_ARCADA #endif @@ -42,26 +60,6 @@ #endif #endif - -/* This sketch demonstrates Pairing process using dynamic Passkey. - * This sketch is essentially the same as bleuart.ino except the BLE Uart - * service requires Security Mode with Man-In-The-Middle protection i.e - * - * BLE Pairing procedure is complicated, it is advisable for users to go through - * these articles to get familiar with the procedure and terminology - * - https://www.bluetooth.com/blog/bluetooth-pairing-part-1-pairing-feature-exchange/ - * - https://www.bluetooth.com/blog/bluetooth-pairing-part-2-key-generation-methods/ - * - https://www.bluetooth.com/blog/bluetooth-pairing-passkey-entry/ - * - https://www.bluetooth.com/blog/bluetooth-pairing-part-4/ - */ - -/* This sketch demonstrates the "Image Upload" feature of Bluefruit Mobile App. - * Following TFT Display are supported - * - Circuit Playground Bluefruit: https://www.adafruit.com/product/4333 - * - TFT Gizmo : https://www.adafruit.com/product/4367 - * - Adafruit CLUE : https://www.adafruit.com/product/4500 - */ - // BLE Service BLEUart bleuart; // uart over ble @@ -99,15 +97,6 @@ void setup() Bluefruit.begin(); Bluefruit.setTxPower(4); // Check bluefruit.h for supported values - // clear bonds if BUTTON A is pressed -// Serial.println("Hold button A to clear bonds ..... "); -// delay(2000); -// if (0 == digitalRead(PIN_BUTTON1)) -// { -// Serial.println("Clear all central bonds"); -// Bluefruit.Periph.clearBonds(); -// } - /* To use dynamic PassKey for pairing, we need to have * - IO capacities at least DISPPLAY * - Display only: user have to enter 6-digit passkey on their phone @@ -278,6 +267,10 @@ bool pairing_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6], bo uint32_t justReleased; do { + // Disconnected while waiting for input + if ( !Bluefruit.connected(conn_handle) ) break; + + // time out if ( millis() > start_time + 30000 ) break; arcada.readButtons(); @@ -294,6 +287,10 @@ bool pairing_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6], bo // wait until either button is pressed (30 seconds timeout) while( digitalRead(BUTTON_YES) && digitalRead(BUTTON_NO) ) { + // Disconnected while waiting for input + if ( !Bluefruit.connected(conn_handle) ) break; + + // time out if ( millis() > start_time + 30000 ) break; } From cb1a45498b2fcbb8cfa025f8f8ebf0d17cefcc43 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 19 Mar 2020 15:18:13 +0700 Subject: [PATCH 61/74] try to fix some ci --- .github/workflows/githubci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/githubci.yml b/.github/workflows/githubci.yml index e04798053..ab4ed856d 100644 --- a/.github/workflows/githubci.yml +++ b/.github/workflows/githubci.yml @@ -57,7 +57,7 @@ jobs: rm -r $HOME/$BSP_PATH/* ln -s $GITHUB_WORKSPACE $HOME/$BSP_PATH/$BSP_VERSION # Install library dependency - arduino-cli lib install "Adafruit AHRS" "Adafruit APDS9960 Library" "Adafruit BMP280 Library" "Adafruit Circuit Playground" "Adafruit EPD" "Adafruit GFX Library" "Adafruit HX8357 Library" "Adafruit ILI9341" "Adafruit LIS3MDL" "Adafruit LSM6DS" "Adafruit NeoPixel" "Adafruit NeoMatrix" "Adafruit nRFCrypto" "Adafruit Sensor Calibration" "Adafruit SHT31 Library" "Adafruit SSD1306" "Adafruit ST7735 and ST7789 Library" "Firmata" "MIDI Library" "SdFat - Adafruit Fork" + arduino-cli lib install "Adafruit AHRS" "Adafruit APDS9960 Library" "Adafruit Arcada Library" "Adafruit BMP280 Library" "Adafruit Circuit Playground" "Adafruit EPD" "Adafruit GFX Library" "Adafruit HX8357 Library" "Adafruit ILI9341" "Adafruit LIS3MDL" "Adafruit LSM6DS" "Adafruit NeoPixel" "Adafruit NeoMatrix" "Adafruit nRFCrypto" "Adafruit Sensor Calibration" "Adafruit SHT31 Library" "Adafruit SSD1306" "Adafruit ST7735 and ST7789 Library" "Firmata" "MIDI Library" "SdFat - Adafruit Fork" - name: Build examples run: python3 tools/build_all.py ${{ matrix.arduino-platform }} From 0391ecac34d129b85d5b485d2b1415f59e2514bd Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 19 Mar 2020 15:52:23 +0700 Subject: [PATCH 62/74] remove Bluefruit::connPaired() and BLEConnection::paired() --- .../Peripheral/hid_camerashutter/hid_camerashutter.ino | 2 +- libraries/Bluefruit52Lib/keywords.txt | 1 - libraries/Bluefruit52Lib/src/BLEConnection.cpp | 5 ----- libraries/Bluefruit52Lib/src/BLEConnection.h | 1 - libraries/Bluefruit52Lib/src/BLEGatt.cpp | 2 +- libraries/Bluefruit52Lib/src/bluefruit.cpp | 6 ------ libraries/Bluefruit52Lib/src/bluefruit.h | 1 - libraries/Bluefruit52Lib/src/services/BLEDfu.cpp | 2 +- 8 files changed, 3 insertions(+), 17 deletions(-) diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/hid_camerashutter/hid_camerashutter.ino b/libraries/Bluefruit52Lib/examples/Peripheral/hid_camerashutter/hid_camerashutter.ino index 3bcabdb8e..da03966d2 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/hid_camerashutter/hid_camerashutter.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/hid_camerashutter/hid_camerashutter.ino @@ -114,7 +114,7 @@ void loop() { BLEConnection* connection = Bluefruit.Connection(conn_hdl); - if ( connection && connection->connected() && connection->paired() ) + if ( connection && connection->connected() && connection->secured() ) { // Turn on red LED when we start sending data digitalWrite(LED_RED, 1); diff --git a/libraries/Bluefruit52Lib/keywords.txt b/libraries/Bluefruit52Lib/keywords.txt index 1e63c8ac5..f1537af89 100644 --- a/libraries/Bluefruit52Lib/keywords.txt +++ b/libraries/Bluefruit52Lib/keywords.txt @@ -69,7 +69,6 @@ disconnect KEYWORD2 setConnInterval KEYWORD2 setConnIntervalMS KEYWORD2 connHandle KEYWORD2 -connPaired KEYWORD2 connInterval KEYWORD2 requestPairing KEYWORD2 clearBonds KEYWORD2 diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.cpp b/libraries/Bluefruit52Lib/src/BLEConnection.cpp index b1418aa81..3bbdf718e 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.cpp +++ b/libraries/Bluefruit52Lib/src/BLEConnection.cpp @@ -83,11 +83,6 @@ bool BLEConnection::connected(void) return _connected; } -bool BLEConnection::paired (void) -{ - return secured(); -} - bool BLEConnection::bonded(void) { return _bonded; diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.h b/libraries/Bluefruit52Lib/src/BLEConnection.h index db7497a27..d940878c3 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.h +++ b/libraries/Bluefruit52Lib/src/BLEConnection.h @@ -74,7 +74,6 @@ class BLEConnection uint16_t handle(void); bool connected(void); - bool paired(void); // todo removed bool bonded(void); bool secured(void); diff --git a/libraries/Bluefruit52Lib/src/BLEGatt.cpp b/libraries/Bluefruit52Lib/src/BLEGatt.cpp index 04bce2ce0..45dc06420 100644 --- a/libraries/Bluefruit52Lib/src/BLEGatt.cpp +++ b/libraries/Bluefruit52Lib/src/BLEGatt.cpp @@ -140,7 +140,7 @@ void BLEGatt::_eventHandler(ble_evt_t* evt) chr->_eventHandler(evt); // Save CCCD if paired - if ( conn->paired() && (evt_id == BLE_GATTS_EVT_WRITE) && (req_handle == chr->handles().cccd_handle) ) + if ( conn->secured() && (evt_id == BLE_GATTS_EVT_WRITE) && (req_handle == chr->handles().cccd_handle) ) { conn->saveCccd(); } diff --git a/libraries/Bluefruit52Lib/src/bluefruit.cpp b/libraries/Bluefruit52Lib/src/bluefruit.cpp index b15c76879..f9838043a 100644 --- a/libraries/Bluefruit52Lib/src/bluefruit.cpp +++ b/libraries/Bluefruit52Lib/src/bluefruit.cpp @@ -618,12 +618,6 @@ uint16_t AdafruitBluefruit::connHandle(void) return _conn_hdl; } -bool AdafruitBluefruit::connPaired(uint16_t conn_hdl) -{ - BLEConnection* conn = Bluefruit.Connection(conn_hdl); - return conn && conn->paired(); -} - uint16_t AdafruitBluefruit::getMaxMtu(uint8_t role) { return (role == BLE_GAP_ROLE_PERIPH) ? _sd_cfg.prph.mtu_max : _sd_cfg.central.mtu_max; diff --git a/libraries/Bluefruit52Lib/src/bluefruit.h b/libraries/Bluefruit52Lib/src/bluefruit.h index 5afa0bd2b..48dff1b88 100644 --- a/libraries/Bluefruit52Lib/src/bluefruit.h +++ b/libraries/Bluefruit52Lib/src/bluefruit.h @@ -166,7 +166,6 @@ class AdafruitBluefruit uint16_t connHandle (void); // Alias to BLEConnection API() - bool connPaired (uint16_t conn_hdl); bool disconnect (uint16_t conn_hdl); uint16_t getMaxMtu(uint8_t role); diff --git a/libraries/Bluefruit52Lib/src/services/BLEDfu.cpp b/libraries/Bluefruit52Lib/src/services/BLEDfu.cpp index 70abcd28d..78f34f862 100644 --- a/libraries/Bluefruit52Lib/src/services/BLEDfu.cpp +++ b/libraries/Bluefruit52Lib/src/services/BLEDfu.cpp @@ -137,7 +137,7 @@ static void bledfu_control_wr_authorize_cb(uint16_t conn_hdl, BLECharacteristic* // Get Bond Data or using Address if not bonded peer_data->addr = conn->getPeerAddr(); - if ( conn->paired() ) + if ( conn->secured() ) { bond_keys_t bkeys; if ( conn->loadBondKey(&bkeys) ) From 1a6a88a556d32cc4ad97b35357b03fa62bee5ab8 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 19 Mar 2020 16:18:41 +0700 Subject: [PATCH 63/74] fix ci for feather52832 --- .../Central/central_pairing/central_pairing.ino | 1 - .../pairing_passkey/pairing_passkey.ino | 1 - libraries/Bluefruit52Lib/src/BLEPairing.cpp | 16 ++++++++-------- libraries/Bluefruit52Lib/src/BLEPairing.h | 3 ++- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino b/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino index 673856a94..50c24f06b 100644 --- a/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino +++ b/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino @@ -39,7 +39,6 @@ #include #include #include -#include #ifdef USE_ARCADA #include diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino index e064f8fa0..426779945 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino @@ -37,7 +37,6 @@ #include #include #include -#include #ifdef USE_ARCADA #include diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.cpp b/libraries/Bluefruit52Lib/src/BLEPairing.cpp index c4b4e8b47..b4edbdfa2 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.cpp +++ b/libraries/Bluefruit52Lib/src/BLEPairing.cpp @@ -86,7 +86,6 @@ BLEPairing::BLEPairing(void) bool BLEPairing::begin(void) { - #ifdef NRF_CRYPTOCELL // Initalize Crypto lib for LESC (safe to call multiple times) nRFCrypto.begin(); @@ -275,22 +274,21 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) .p_enc_key = &_bond_keys.own_enc, .p_id_key = NULL, .p_sign_key = NULL, - .p_pk = (ble_gap_lesc_p256_pk_t*) (_pubkey+1) + .p_pk = NULL }, .keys_peer = { .p_enc_key = &_bond_keys.peer_enc, .p_id_key = &_bond_keys.peer_id, .p_sign_key = NULL, - .p_pk = (ble_gap_lesc_p256_pk_t*) (_peer_pubkey+1) + .p_pk = NULL } }; - // use LESC when both support it - if ( peer->lesc && _sec_param.lesc ) - { -// keyset. - } + #ifdef NRF_CRYPTOCELL + keyset.keys_own.p_pk = (ble_gap_lesc_p256_pk_t*) (_pubkey+1); + keyset.keys_peer.p_pk = (ble_gap_lesc_p256_pk_t*) (_peer_pubkey+1); + #endif VERIFY_STATUS(sd_ble_gap_sec_params_reply(conn_hdl, BLE_GAP_SEC_STATUS_SUCCESS, conn->getRole() == BLE_GAP_ROLE_PERIPH ? &_sec_param : NULL, &keyset), ); @@ -310,6 +308,7 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) } break; +#ifdef NRF_CRYPTOCELL case BLE_GAP_EVT_LESC_DHKEY_REQUEST: { ble_gap_evt_lesc_dhkey_request_t* dhkey_req = &evt->evt.gap_evt.params.lesc_dhkey_request; @@ -348,6 +347,7 @@ void BLEPairing::_eventHandler(ble_evt_t* evt) sd_ble_gap_lesc_dhkey_reply(conn_hdl, &dhkey); } break; +#endif // Pairing process completed case BLE_GAP_EVT_AUTH_STATUS: diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.h b/libraries/Bluefruit52Lib/src/BLEPairing.h index 57705bf4a..8f17bb70d 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.h +++ b/libraries/Bluefruit52Lib/src/BLEPairing.h @@ -73,10 +73,11 @@ class BLEPairing private: ble_gap_sec_params_t _sec_param; +#ifdef NRF_CRYPTOCELL nRFCrypto_ECC_PrivateKey _private_key; - uint8_t _pubkey[1+BLE_GAP_LESC_P256_PK_LEN]; // our public key: 1 header + 64 data uint8_t _peer_pubkey[1+BLE_GAP_LESC_P256_PK_LEN]; // peer public key when using LESC +#endif bond_keys_t _bond_keys; // Shared keys with bonded device during securing connection, size ~ 80 bytes From f604a2c88911df8429abf45881ccc376f793df14 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 19 Mar 2020 17:15:22 +0700 Subject: [PATCH 64/74] fix ci --- .../Central/central_pairing/central_pairing.ino | 16 ++++++++-------- .../ancs_arcada/.cluenrf52840.test.only | 0 .../ancs_arcada/.cplaynrf52840.test.only | 0 3 files changed, 8 insertions(+), 8 deletions(-) create mode 100644 libraries/Bluefruit52Lib/examples/Peripheral/ancs_arcada/.cluenrf52840.test.only create mode 100644 libraries/Bluefruit52Lib/examples/Peripheral/ancs_arcada/.cplaynrf52840.test.only diff --git a/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino b/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino index 50c24f06b..3389a5c6d 100644 --- a/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino +++ b/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino @@ -89,14 +89,14 @@ void setup() Bluefruit.begin(0, 1); // clear bonds if BUTTON A is pressed - Serial.println("Hold button A to clear bonds ..... "); - Serial.flush(); - delay(2000); - if (0 == digitalRead(PIN_BUTTON1)) - { - Serial.println("Clear all central bonds"); - Bluefruit.Central.clearBonds(); - } +// Serial.println("Hold button A to clear bonds ..... "); +// Serial.flush(); +// delay(2000); +// if (0 == digitalRead(PIN_BUTTON1)) +// { +// Serial.println("Clear all central bonds"); +// Bluefruit.Central.clearBonds(); +// } // To use dynamic PassKey for pairing, we need to have // - IO capacities at least DISPPLAY diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/ancs_arcada/.cluenrf52840.test.only b/libraries/Bluefruit52Lib/examples/Peripheral/ancs_arcada/.cluenrf52840.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/ancs_arcada/.cplaynrf52840.test.only b/libraries/Bluefruit52Lib/examples/Peripheral/ancs_arcada/.cplaynrf52840.test.only new file mode 100644 index 000000000..e69de29bb From 5e78aa3a73b1cc01c2ac31d9654a454bafbf2128 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 19 Mar 2020 17:38:39 +0700 Subject: [PATCH 65/74] rename BLEPairing to BLESecurity --- libraries/Bluefruit52Lib/src/BLECentral.cpp | 3 +-- .../src/{BLEPairing.cpp => BLESecurity.cpp} | 26 +++++++++---------- .../src/{BLEPairing.h => BLESecurity.h} | 10 +++---- libraries/Bluefruit52Lib/src/bluefruit.h | 4 +-- 4 files changed, 21 insertions(+), 22 deletions(-) rename libraries/Bluefruit52Lib/src/{BLEPairing.cpp => BLESecurity.cpp} (93%) rename libraries/Bluefruit52Lib/src/{BLEPairing.h => BLESecurity.h} (96%) diff --git a/libraries/Bluefruit52Lib/src/BLECentral.cpp b/libraries/Bluefruit52Lib/src/BLECentral.cpp index d8210d66b..edee92594 100644 --- a/libraries/Bluefruit52Lib/src/BLECentral.cpp +++ b/libraries/Bluefruit52Lib/src/BLECentral.cpp @@ -145,8 +145,7 @@ void BLECentral::_eventHandler(ble_evt_t* evt) bond_keys_t ltkey; if ( conn->loadBondKey(<key) ) { - BLEPairing* secure = &Bluefruit.Pairing; - secure->_encrypt(conn_hdl, <key); + Bluefruit.Pairing._encrypt(conn_hdl, <key); } } break; diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.cpp b/libraries/Bluefruit52Lib/src/BLESecurity.cpp similarity index 93% rename from libraries/Bluefruit52Lib/src/BLEPairing.cpp rename to libraries/Bluefruit52Lib/src/BLESecurity.cpp index b4edbdfa2..b44434a41 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.cpp +++ b/libraries/Bluefruit52Lib/src/BLESecurity.cpp @@ -65,7 +65,7 @@ static void swap_endian(uint8_t data[], uint32_t nbytes) } } -static void _passkey_display_cabllack_dfr(BLEPairing::pair_passkey_cb_t func, uint16_t conn_hdl, uint8_t const passkey[6], bool match_request) +static void _passkey_display_cabllack_dfr(BLESecurity::pair_passkey_cb_t func, uint16_t conn_hdl, uint8_t const passkey[6], bool match_request) { bool matched = func(conn_hdl, passkey, match_request); @@ -76,7 +76,7 @@ static void _passkey_display_cabllack_dfr(BLEPairing::pair_passkey_cb_t func, ui } } -BLEPairing::BLEPairing(void) +BLESecurity::BLESecurity(void) { _sec_param = _sec_param_default; _passkey_cb = NULL; @@ -84,7 +84,7 @@ BLEPairing::BLEPairing(void) _secured_cb = NULL; } -bool BLEPairing::begin(void) +bool BLESecurity::begin(void) { #ifdef NRF_CRYPTOCELL // Initalize Crypto lib for LESC (safe to call multiple times) @@ -113,7 +113,7 @@ bool BLEPairing::begin(void) return true; } -void BLEPairing::setIOCaps(bool display, bool yes_no, bool keyboard) +void BLESecurity::setIOCaps(bool display, bool yes_no, bool keyboard) { uint8_t io_caps = BLE_GAP_IO_CAPS_NONE; @@ -138,7 +138,7 @@ void BLEPairing::setIOCaps(bool display, bool yes_no, bool keyboard) _sec_param.io_caps = io_caps; } -void BLEPairing::setMITM(bool enabled) +void BLESecurity::setMITM(bool enabled) { _sec_param.mitm = (enabled ? 1 : 0); } @@ -149,7 +149,7 @@ void BLEPairing::setMITM(bool enabled) * * To check if it matches we recreate local AES Hash with IRK to compare with */ -bool BLEPairing::resolveAddress(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * irk) +bool BLESecurity::resolveAddress(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * irk) { VERIFY(p_addr->addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE); @@ -177,7 +177,7 @@ bool BLEPairing::resolveAddress(ble_gap_addr_t const * p_addr, ble_gap_irk_t con } // Use Legacy SC static Passkey -bool BLEPairing::setPIN(const char* pin) +bool BLESecurity::setPIN(const char* pin) { VERIFY(pin && strlen(pin) == BLE_GAP_PASSKEY_LEN); @@ -197,7 +197,7 @@ bool BLEPairing::setPIN(const char* pin) } // Pairing using LESC with peripheral display -bool BLEPairing::setPasskeyCallback(pair_passkey_cb_t fp) +bool BLESecurity::setPasskeyCallback(pair_passkey_cb_t fp) { _passkey_cb = fp; @@ -207,23 +207,23 @@ bool BLEPairing::setPasskeyCallback(pair_passkey_cb_t fp) return true; } -void BLEPairing::setCompleteCallback(pair_complete_cb_t fp) +void BLESecurity::setCompleteCallback(pair_complete_cb_t fp) { _complete_cb = fp; } -void BLEPairing::setSecuredCallback(pair_secured_cb_t fp) +void BLESecurity::setSecuredCallback(pair_secured_cb_t fp) { _secured_cb = fp; } -bool BLEPairing::_authenticate(uint16_t conn_hdl) +bool BLESecurity::_authenticate(uint16_t conn_hdl) { VERIFY_STATUS(sd_ble_gap_authenticate(conn_hdl, &_sec_param ), false); return true; } -bool BLEPairing::_encrypt(uint16_t conn_hdl, bond_keys_t const* ltkey) +bool BLESecurity::_encrypt(uint16_t conn_hdl, bond_keys_t const* ltkey) { // LESC use own key, Legacy use peer key ble_gap_enc_key_t const* enc_key = ltkey->own_enc.enc_info.lesc ? <key->own_enc : <key->peer_enc; @@ -249,7 +249,7 @@ bool BLEPairing::_encrypt(uint16_t conn_hdl, bond_keys_t const* ltkey) * 3. Connection is secured BLE_GAP_EVT_CONN_SEC_UPDATE */ //--------------------------------------------------------------------+ -void BLEPairing::_eventHandler(ble_evt_t* evt) +void BLESecurity::_eventHandler(ble_evt_t* evt) { uint16_t const conn_hdl = evt->evt.common_evt.conn_handle; BLEConnection* conn = Bluefruit.Connection(conn_hdl); diff --git a/libraries/Bluefruit52Lib/src/BLEPairing.h b/libraries/Bluefruit52Lib/src/BLESecurity.h similarity index 96% rename from libraries/Bluefruit52Lib/src/BLEPairing.h rename to libraries/Bluefruit52Lib/src/BLESecurity.h index 8f17bb70d..6c10cbb07 100644 --- a/libraries/Bluefruit52Lib/src/BLEPairing.h +++ b/libraries/Bluefruit52Lib/src/BLESecurity.h @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#ifndef BLEPAIRING_H_ -#define BLEPAIRING_H_ +#ifndef BLESECURITY_H_ +#define BLESECURITY_H_ #include "bluefruit_common.h" #include "utility/bonding.h" @@ -32,14 +32,14 @@ #include "Adafruit_nRFCrypto.h" #endif -class BLEPairing +class BLESecurity { public: typedef bool (*pair_passkey_cb_t ) (uint16_t conn_hdl, uint8_t const passkey[6], bool match_request); typedef void (*pair_complete_cb_t) (uint16_t conn_hdl, uint8_t auth_status); typedef void (*pair_secured_cb_t) (uint16_t conn_hdl); - BLEPairing(void); + BLESecurity(void); bool begin(void); @@ -86,4 +86,4 @@ class BLEPairing pair_secured_cb_t _secured_cb; }; -#endif /* BLEPAIRING_H_ */ +#endif /* BLESECURITY_H_ */ diff --git a/libraries/Bluefruit52Lib/src/bluefruit.h b/libraries/Bluefruit52Lib/src/bluefruit.h index 48dff1b88..9a7fb4ba8 100644 --- a/libraries/Bluefruit52Lib/src/bluefruit.h +++ b/libraries/Bluefruit52Lib/src/bluefruit.h @@ -55,7 +55,7 @@ #include "BLEDiscovery.h" #include "BLEConnection.h" #include "BLEGatt.h" -#include "BLEPairing.h" +#include "BLESecurity.h" // Services #include "services/BLEDis.h" @@ -111,7 +111,7 @@ class AdafruitBluefruit *------------------------------------------------------------------*/ BLEPeriph Periph; BLECentral Central; - BLEPairing Pairing; + BLESecurity Pairing; BLEGatt Gatt; BLEAdvertising Advertising; From c322f4c8342cb4c87d0474dde67952d6610c155e Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 19 Mar 2020 17:39:40 +0700 Subject: [PATCH 66/74] rename Bluefruit.Pairing to Bluefruit.Security --- .../examples/Central/central_hid/central_hid.ino | 2 +- .../examples/Central/central_pairing/central_pairing.ino | 8 ++++---- .../Bluefruit52Lib/examples/Peripheral/ancs/ancs.ino | 2 +- .../examples/Peripheral/ancs_arcada/ancs_arcada.ino | 2 +- .../examples/Peripheral/ancs_oled/ancs_oled.ino | 2 +- .../examples/Peripheral/client_cts/client_cts.ino | 2 +- .../Peripheral/client_cts_oled/client_cts_oled.ino | 2 +- .../Peripheral/pairing_passkey/pairing_passkey.ino | 8 ++++---- .../examples/Peripheral/pairing_pin/pairing_pin.ino | 2 +- libraries/Bluefruit52Lib/src/BLECentral.cpp | 2 +- libraries/Bluefruit52Lib/src/BLEConnection.cpp | 4 ++-- libraries/Bluefruit52Lib/src/bluefruit.cpp | 4 ++-- libraries/Bluefruit52Lib/src/bluefruit.h | 2 +- libraries/Bluefruit52Lib/src/utility/bonding.cpp | 2 +- 14 files changed, 22 insertions(+), 22 deletions(-) diff --git a/libraries/Bluefruit52Lib/examples/Central/central_hid/central_hid.ino b/libraries/Bluefruit52Lib/examples/Central/central_hid/central_hid.ino index 2cf0da081..2020b5492 100644 --- a/libraries/Bluefruit52Lib/examples/Central/central_hid/central_hid.ino +++ b/libraries/Bluefruit52Lib/examples/Central/central_hid/central_hid.ino @@ -56,7 +56,7 @@ void setup() Bluefruit.Central.setDisconnectCallback(disconnect_callback); // Set connection secured callback, invoked when connection is encrypted - Bluefruit.Pairing.setSecuredCallback(connection_secured_callback); + Bluefruit.Security.setSecuredCallback(connection_secured_callback); /* Start Central Scanning * - Enable auto scan if disconnected diff --git a/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino b/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino index 3389a5c6d..9e2b2d419 100644 --- a/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino +++ b/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino @@ -103,14 +103,14 @@ void setup() // - Register callback to display/print dynamic passkey for central // For complete mapping of the IO Capabilities to Key Generation Method, check out this article // https://www.bluetooth.com/blog/bluetooth-pairing-part-2-key-generation-methods/ - Bluefruit.Pairing.setIOCaps(true, true, false); // display = true, yes/no = true, keyboard = false - Bluefruit.Pairing.setPasskeyCallback(pairing_passkey_callback); + Bluefruit.Security.setIOCaps(true, true, false); // display = true, yes/no = true, keyboard = false + Bluefruit.Security.setPasskeyCallback(pairing_passkey_callback); // Set complete callback to print the pairing result - Bluefruit.Pairing.setCompleteCallback(pairing_complete_callback); + Bluefruit.Security.setCompleteCallback(pairing_complete_callback); // Set connection secured callback, invoked when connection is encrypted - Bluefruit.Pairing.setSecuredCallback(connection_secured_callback); + Bluefruit.Security.setSecuredCallback(connection_secured_callback); // Init BLE Central Uart Serivce clientUart.begin(); diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/ancs/ancs.ino b/libraries/Bluefruit52Lib/examples/Peripheral/ancs/ancs.ino index 6719c4e82..11551661f 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/ancs/ancs.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/ancs/ancs.ino @@ -57,7 +57,7 @@ void setup() Bluefruit.Periph.setDisconnectCallback(disconnect_callback); // Set connection secured callback, invoked when connection is encrypted - Bluefruit.Pairing.setSecuredCallback(connection_secured_callback); + Bluefruit.Security.setSecuredCallback(connection_secured_callback); // Configure DIS client bleClientDis.begin(); diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/ancs_arcada/ancs_arcada.ino b/libraries/Bluefruit52Lib/examples/Peripheral/ancs_arcada/ancs_arcada.ino index ff6ad5f2b..c1c1bcbba 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/ancs_arcada/ancs_arcada.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/ancs_arcada/ancs_arcada.ino @@ -84,7 +84,7 @@ void setup() Bluefruit.Periph.setDisconnectCallback(disconnect_callback); // Set connection secured callback, invoked when connection is encrypted - Bluefruit.Pairing.setSecuredCallback(connection_secured_callback); + Bluefruit.Security.setSecuredCallback(connection_secured_callback); // Configure and Start Service bleancs.begin(); diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/ancs_oled/ancs_oled.ino b/libraries/Bluefruit52Lib/examples/Peripheral/ancs_oled/ancs_oled.ino index 5b1a2958e..141d8fddd 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/ancs_oled/ancs_oled.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/ancs_oled/ancs_oled.ino @@ -94,7 +94,7 @@ void setup() Bluefruit.Periph.setDisconnectCallback(disconnect_callback); // Set connection secured callback, invoked when connection is encrypted - Bluefruit.Pairing.setSecuredCallback(connection_secured_callback); + Bluefruit.Security.setSecuredCallback(connection_secured_callback); // Configure and Start Service bleancs.begin(); diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/client_cts/client_cts.ino b/libraries/Bluefruit52Lib/examples/Peripheral/client_cts/client_cts.ino index e7507bcd2..15458b780 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/client_cts/client_cts.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/client_cts/client_cts.ino @@ -53,7 +53,7 @@ void setup() Bluefruit.Periph.setDisconnectCallback(disconnect_callback); // Set connection secured callback, invoked when connection is encrypted - Bluefruit.Pairing.setSecuredCallback(connection_secured_callback); + Bluefruit.Security.setSecuredCallback(connection_secured_callback); // Configure CTS client bleCTime.begin(); diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/client_cts_oled/client_cts_oled.ino b/libraries/Bluefruit52Lib/examples/Peripheral/client_cts_oled/client_cts_oled.ino index 24657468c..b8e21451c 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/client_cts_oled/client_cts_oled.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/client_cts_oled/client_cts_oled.ino @@ -59,7 +59,7 @@ void setup() Bluefruit.Periph.setDisconnectCallback(disconnect_callback); // Set connection secured callback, invoked when connection is encrypted - Bluefruit.Pairing.setSecuredCallback(connection_secured_callback); + Bluefruit.Security.setSecuredCallback(connection_secured_callback); // Configure CTS client bleCTime.begin(); diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino index 426779945..3a9d62d7a 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino @@ -105,14 +105,14 @@ void setup() * For complete mapping of the IO Capabilities to Key Generation Method, check out this article * https://www.bluetooth.com/blog/bluetooth-pairing-part-2-key-generation-methods/ */ - Bluefruit.Pairing.setIOCaps(true, true, false); // display = true, yes/no = true, keyboard = false - Bluefruit.Pairing.setPasskeyCallback(pairing_passkey_callback); + Bluefruit.Security.setIOCaps(true, true, false); // display = true, yes/no = true, keyboard = false + Bluefruit.Security.setPasskeyCallback(pairing_passkey_callback); // Set complete callback to print the pairing result - Bluefruit.Pairing.setCompleteCallback(pairing_complete_callback); + Bluefruit.Security.setCompleteCallback(pairing_complete_callback); // Set connection secured callback, invoked when connection is encrypted - Bluefruit.Pairing.setSecuredCallback(connection_secured_callback); + Bluefruit.Security.setSecuredCallback(connection_secured_callback); Bluefruit.Periph.setConnectCallback(connect_callback); Bluefruit.Periph.setDisconnectCallback(disconnect_callback); diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_pin/pairing_pin.ino b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_pin/pairing_pin.ino index b92cd0d26..56e42bd26 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_pin/pairing_pin.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_pin/pairing_pin.ino @@ -51,7 +51,7 @@ void setup() Bluefruit.setName("Bluefruit52"); Serial.println("Setting pairing PIN to: " PAIRING_PIN); - Bluefruit.Pairing.setPIN(PAIRING_PIN); + Bluefruit.Security.setPIN(PAIRING_PIN); Bluefruit.Periph.setConnectCallback(connect_callback); Bluefruit.Periph.setDisconnectCallback(disconnect_callback); diff --git a/libraries/Bluefruit52Lib/src/BLECentral.cpp b/libraries/Bluefruit52Lib/src/BLECentral.cpp index edee92594..2b9cf220f 100644 --- a/libraries/Bluefruit52Lib/src/BLECentral.cpp +++ b/libraries/Bluefruit52Lib/src/BLECentral.cpp @@ -145,7 +145,7 @@ void BLECentral::_eventHandler(ble_evt_t* evt) bond_keys_t ltkey; if ( conn->loadBondKey(<key) ) { - Bluefruit.Pairing._encrypt(conn_hdl, <key); + Bluefruit.Security._encrypt(conn_hdl, <key); } } break; diff --git a/libraries/Bluefruit52Lib/src/BLEConnection.cpp b/libraries/Bluefruit52Lib/src/BLEConnection.cpp index 3bbdf718e..67a36ac8d 100644 --- a/libraries/Bluefruit52Lib/src/BLEConnection.cpp +++ b/libraries/Bluefruit52Lib/src/BLEConnection.cpp @@ -120,7 +120,7 @@ uint8_t BLEConnection::getPHY(void) ble_gap_addr_t BLEConnection::getPeerAddr (void) { - return _peer_addr; + return _bonded ? _bond_id_addr : _peer_addr; } uint16_t BLEConnection::getPeerName(char* buf, uint16_t bufsize) @@ -270,7 +270,7 @@ bool BLEConnection::requestPairing(void) // skip if already paired if ( secured() ) return true; - return Bluefruit.Pairing._authenticate(_conn_hdl); + return Bluefruit.Security._authenticate(_conn_hdl); } bool BLEConnection::waitForIndicateConfirm(void) diff --git a/libraries/Bluefruit52Lib/src/bluefruit.cpp b/libraries/Bluefruit52Lib/src/bluefruit.cpp index f9838043a..38ad82e1e 100644 --- a/libraries/Bluefruit52Lib/src/bluefruit.cpp +++ b/libraries/Bluefruit52Lib/src/bluefruit.cpp @@ -437,7 +437,7 @@ bool AdafruitBluefruit::begin(uint8_t prph_count, uint8_t central_count) // Init Peripheral role VERIFY( Periph.begin() ); - Pairing.begin(); + Security.begin(); // Default device name ble_gap_conn_sec_mode_t sec_mode = BLE_SECMODE_OPEN; @@ -748,7 +748,7 @@ void AdafruitBluefruit::_ble_handler(ble_evt_t* evt) if ( conn ) { conn->_eventHandler(evt); - Pairing._eventHandler(evt); + Security._eventHandler(evt); } switch(evt->header.evt_id) diff --git a/libraries/Bluefruit52Lib/src/bluefruit.h b/libraries/Bluefruit52Lib/src/bluefruit.h index 9a7fb4ba8..147b04fdb 100644 --- a/libraries/Bluefruit52Lib/src/bluefruit.h +++ b/libraries/Bluefruit52Lib/src/bluefruit.h @@ -111,7 +111,7 @@ class AdafruitBluefruit *------------------------------------------------------------------*/ BLEPeriph Periph; BLECentral Central; - BLESecurity Pairing; + BLESecurity Security; BLEGatt Gatt; BLEAdvertising Advertising; diff --git a/libraries/Bluefruit52Lib/src/utility/bonding.cpp b/libraries/Bluefruit52Lib/src/utility/bonding.cpp index 7f53b319a..8810c8997 100644 --- a/libraries/Bluefruit52Lib/src/utility/bonding.cpp +++ b/libraries/Bluefruit52Lib/src/utility/bonding.cpp @@ -182,7 +182,7 @@ bool bond_load_keys(uint8_t role, ble_gap_addr_t* addr, bond_keys_t* bkeys) if ( keylen == sizeof(bond_keys_t) ) { file.read((uint8_t*) bkeys, keylen); - if ( Bluefruit.Pairing.resolveAddress(addr, &bkeys->peer_id.id_info) ) + if ( Bluefruit.Security.resolveAddress(addr, &bkeys->peer_id.id_info) ) { ret = true; BOND_LOG("Loaded keys from file %s/%s", dpath, file.name()); From a860206275466e7e0d7dd565bf55fe5d88d25079 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 19 Mar 2020 17:42:11 +0700 Subject: [PATCH 67/74] callback rename --- .../Central/central_pairing/central_pairing.ino | 4 ++-- .../Peripheral/pairing_passkey/pairing_passkey.ino | 4 ++-- libraries/Bluefruit52Lib/src/BLESecurity.cpp | 6 +++--- libraries/Bluefruit52Lib/src/BLESecurity.h | 10 +++++----- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino b/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino index 9e2b2d419..ab5043c4a 100644 --- a/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino +++ b/libraries/Bluefruit52Lib/examples/Central/central_pairing/central_pairing.ino @@ -104,10 +104,10 @@ void setup() // For complete mapping of the IO Capabilities to Key Generation Method, check out this article // https://www.bluetooth.com/blog/bluetooth-pairing-part-2-key-generation-methods/ Bluefruit.Security.setIOCaps(true, true, false); // display = true, yes/no = true, keyboard = false - Bluefruit.Security.setPasskeyCallback(pairing_passkey_callback); + Bluefruit.Security.setPairPasskeyCallback(pairing_passkey_callback); // Set complete callback to print the pairing result - Bluefruit.Security.setCompleteCallback(pairing_complete_callback); + Bluefruit.Security.setPairCompleteCallback(pairing_complete_callback); // Set connection secured callback, invoked when connection is encrypted Bluefruit.Security.setSecuredCallback(connection_secured_callback); diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino index 3a9d62d7a..6b5f852a4 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino @@ -106,10 +106,10 @@ void setup() * https://www.bluetooth.com/blog/bluetooth-pairing-part-2-key-generation-methods/ */ Bluefruit.Security.setIOCaps(true, true, false); // display = true, yes/no = true, keyboard = false - Bluefruit.Security.setPasskeyCallback(pairing_passkey_callback); + Bluefruit.Security.setPairPasskeyCallback(pairing_passkey_callback); // Set complete callback to print the pairing result - Bluefruit.Security.setCompleteCallback(pairing_complete_callback); + Bluefruit.Security.setPairCompleteCallback(pairing_complete_callback); // Set connection secured callback, invoked when connection is encrypted Bluefruit.Security.setSecuredCallback(connection_secured_callback); diff --git a/libraries/Bluefruit52Lib/src/BLESecurity.cpp b/libraries/Bluefruit52Lib/src/BLESecurity.cpp index b44434a41..f0f58cf96 100644 --- a/libraries/Bluefruit52Lib/src/BLESecurity.cpp +++ b/libraries/Bluefruit52Lib/src/BLESecurity.cpp @@ -197,7 +197,7 @@ bool BLESecurity::setPIN(const char* pin) } // Pairing using LESC with peripheral display -bool BLESecurity::setPasskeyCallback(pair_passkey_cb_t fp) +bool BLESecurity::setPairPasskeyCallback(pair_passkey_cb_t fp) { _passkey_cb = fp; @@ -207,12 +207,12 @@ bool BLESecurity::setPasskeyCallback(pair_passkey_cb_t fp) return true; } -void BLESecurity::setCompleteCallback(pair_complete_cb_t fp) +void BLESecurity::setPairCompleteCallback(pair_complete_cb_t fp) { _complete_cb = fp; } -void BLESecurity::setSecuredCallback(pair_secured_cb_t fp) +void BLESecurity::setSecuredCallback(secured_conn_cb_t fp) { _secured_cb = fp; } diff --git a/libraries/Bluefruit52Lib/src/BLESecurity.h b/libraries/Bluefruit52Lib/src/BLESecurity.h index 6c10cbb07..2a3ea098c 100644 --- a/libraries/Bluefruit52Lib/src/BLESecurity.h +++ b/libraries/Bluefruit52Lib/src/BLESecurity.h @@ -37,7 +37,7 @@ class BLESecurity public: typedef bool (*pair_passkey_cb_t ) (uint16_t conn_hdl, uint8_t const passkey[6], bool match_request); typedef void (*pair_complete_cb_t) (uint16_t conn_hdl, uint8_t auth_status); - typedef void (*pair_secured_cb_t) (uint16_t conn_hdl); + typedef void (*secured_conn_cb_t) (uint16_t conn_hdl); BLESecurity(void); @@ -56,9 +56,9 @@ class BLESecurity bool resolveAddress(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * irk); //------------- Callbacks -------------// - bool setPasskeyCallback(pair_passkey_cb_t fp); - void setCompleteCallback(pair_complete_cb_t fp); - void setSecuredCallback(pair_secured_cb_t fp); + bool setPairPasskeyCallback(pair_passkey_cb_t fp); + void setPairCompleteCallback(pair_complete_cb_t fp); + void setSecuredCallback(secured_conn_cb_t fp); /*------------------------------------------------------------------*/ /* INTERNAL USAGE ONLY @@ -83,7 +83,7 @@ class BLESecurity pair_passkey_cb_t _passkey_cb; pair_complete_cb_t _complete_cb; - pair_secured_cb_t _secured_cb; + secured_conn_cb_t _secured_cb; }; #endif /* BLESECURITY_H_ */ From 28eba0c780766b7503b3322cee9764514379abc6 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 19 Mar 2020 19:02:18 +0700 Subject: [PATCH 68/74] enhance BLEService::setPermission(read,write) --- README.md | 10 ++-- changelog.md | 50 +++++++++++++++++++ .../pairing_passkey/pairing_passkey.ino | 2 +- .../Peripheral/pairing_pin/pairing_pin.ino | 2 +- .../Bluefruit52Lib/src/BLECharacteristic.cpp | 13 +++-- libraries/Bluefruit52Lib/src/BLEService.cpp | 13 +++-- libraries/Bluefruit52Lib/src/BLEService.h | 7 +-- 7 files changed, 77 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 0d0f97811..d3e5ba447 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Following boards are also included but are not officially supported: - [Nordic nRF52840DK PCA10056](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK) - [Particle Xenon](https://store.particle.io/products/xenon) +- [Raytac MDBT50Q-RX Dongle](https://www.raytac.com/product/ins.php?index_id=89) ## BSP Installation @@ -49,7 +50,7 @@ There are two methods that you can use to install this BSP. We highly recommend ### Adafruit's nrfutil tools -[adafruit-nrfutil](https://github.com/adafruit/Adafruit_nRF52_nrfutil) (derived from Nordic pc-nrfutil) is needed to upload sketch via serial port. +[adafruit-nrfutil](https://github.com/adafruit/Adafruit_nRF52_nrfutil) (derived from Nordic [pc-nrfutil](https://github.com/NordicSemiconductor/pc-nrfutil)) is needed to upload sketch via serial port. - For Windows and macOS, pre-built executable binaries are included in the BSP at `tools/adafruit-nrfutil/`. It should work out of the box. - Linux user need to run follow command to install it from PyPi @@ -117,8 +118,7 @@ which in turn is based on the [Arduino SAMD Core](https://github.com/arduino/Ard The following libraries are used: -- adafruit-nrfutil is based on Nordic Semiconductor ASA's [pc-nrfutil](https://github.com/NordicSemiconductor/pc-nrfutil) -- [freeRTOS](https://www.freertos.org/) as operating system -- [tinyusb](https://github.com/hathach/tinyusb) as usb stack +- [FreeRTOS](https://www.freertos.org/) as operating system +- [LittleFS](https://github.com/ARMmbed/littlefs) for internal file system - [nrfx](https://github.com/NordicSemiconductor/nrfx) for peripherals driver -- [littlefs](https://github.com/ARMmbed/littlefs) for internal file system +- [TinyUSB](https://github.com/hathach/tinyusb) as usb stack diff --git a/changelog.md b/changelog.md index 88c89b084..01a9b9de0 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,55 @@ # Adafruit nRF52 Arduino Core Changelog +## 0.20.0 + +This version implement comprehensive pairing with LESC and Legacy using dynamic & staic Passkey. + +- Support static passkey (Legacy only) +- Support LESC on nRF52840 using hardware-accelerated ARM CryptoCell CC310 provided by [Adafruit_nRFCypto](https://github.com/adafruit/Adafruit_nRFCrypto), therefore nRFCrypto library must be installed +- Rework bonding mechanism to use IRK for peer finding. It is advisable to run `clearbonds` example to clean up bond files of previous version + +### BLESecurity + +A new class BLESecurity (access with Bluefruit.Security) is added to handle security and pairing. + +- **setPIN()** to set static passkey, this will force to use Legacy Pairing +- **setIOCaps()** to congiure IO capacities +- **setMITM()** to enable/disable Man in The Middle protection (passkey), it is auto-enabled when using passkey +- **setPairPasskeyCallback()** to register callback for displaying pairing passkey to user +- **setPairCompleteCallback()** to register callback for the result of pairing procedure (succeeded or failed) +- **setSecuredCallback()** to register callback which invoked when connection is secured. This happens after he pairing procedure is complete, or we re-connect with preivously bonded peer device + +### Other Changes + +**BLECentral** + +- will automatically use stored Long Term Key to secure connection if paired/bonded with device previously + +**Bluefruit** + +- Bluefruit::requestPairing() is removed, please use the BLEConnection::requestPairing() instead +- Bluefruit::connPaired() is removed, please use BLEConnection::secure() instead +- Default Device name is USB_PRODUCT if available e.g CLUE, Circuit Playground Bluefruit, Feather nRF52840 Express etc ... + +**BLEService** + +- Added setPermission() + +**BLEConnection** + +- BLEConnection::requestPairing() is now non-blocking, it will return right after sending request to peer device. Previously it is blocked until the pairing process is complete. +- Added BLEConnection::secured() to check if the connection is secured/encrypted +- Added BLEConnection::bonded() to check if we store Longterm Key with current peer +- Removed BLEConnection:paried(), user should either use secured() or bonded() depending on the context +- If bonded, getPeerAddr() will return peer public address instead of random address. + +**New Example Sketches** + +- **pairing_pin** to use static PIN for peripheral role +- **pairing_passkey** to use dyanmic Passkey for pairing. On Arcada compatible device such as `CLUE` or `Circuit Playground Bluefruit`, TFT display will also be used to display passkey. +- **cental_pairing** similar to pairing_passkey but for nRF running central role +- **ancs_arcada** for displaying ancs on arcada such CLUE and/or CPB. + ## 0.19.0 - 2020.03.12 - Add BLECharacteristic::isFixedLen() diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino index 6b5f852a4..5d7d870e3 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino @@ -121,7 +121,7 @@ void setup() // Set Permission to access BLE Uart is to require man-in-the-middle protection // This will cause central to perform pairing with static PIN we set above Serial.println("Configure BLE Uart to require man-in-the-middle protection for PIN pairing"); - bleuart.setPermission(SECMODE_ENC_WITH_MITM); + bleuart.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); bleuart.begin(); #ifdef USE_ARCADA diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_pin/pairing_pin.ino b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_pin/pairing_pin.ino index 56e42bd26..19a714bf1 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_pin/pairing_pin.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_pin/pairing_pin.ino @@ -60,7 +60,7 @@ void setup() // Set Permission to access BLE Uart is to require man-in-the-middle protection // This will cause central to perform pairing with static PIN we set above Serial.println("Configure BLE Uart to require man-in-the-middle protection for PIN pairing"); - bleuart.setPermission(SECMODE_ENC_WITH_MITM); + bleuart.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); bleuart.begin(); // Set up and start advertising diff --git a/libraries/Bluefruit52Lib/src/BLECharacteristic.cpp b/libraries/Bluefruit52Lib/src/BLECharacteristic.cpp index 715293b85..a7c0a267d 100644 --- a/libraries/Bluefruit52Lib/src/BLECharacteristic.cpp +++ b/libraries/Bluefruit52Lib/src/BLECharacteristic.cpp @@ -245,18 +245,21 @@ err_t BLECharacteristic::begin(void) // Correct Read/Write permission according to parent service // Use service permission if it has higher secure mode - SecureMode_t svc_secmode = _service->getPermission(); - ble_gap_conn_sec_mode_t svc_perm; - memcpy(&svc_perm, &svc_secmode, 1); + SecureMode_t svc_rd_secmode, svc_wr_secmod; + _service->getPermission(&svc_rd_secmode, &svc_wr_secmod); + + ble_gap_conn_sec_mode_t svc_rd_perm, svc_wr_perm; + memcpy(&svc_rd_perm, &svc_rd_secmode, 1); + memcpy(&svc_wr_perm, &svc_wr_secmod , 1); if ( _attr_meta.read_perm.sm != 0 ) // skip no access { - _attr_meta.read_perm = max_secmode(_attr_meta.read_perm, svc_perm); + _attr_meta.read_perm = max_secmode(_attr_meta.read_perm, svc_rd_perm); } if ( _attr_meta.write_perm.sm != 0 ) // skip no access { - _attr_meta.write_perm = max_secmode(_attr_meta.write_perm, svc_perm); + _attr_meta.write_perm = max_secmode(_attr_meta.write_perm, svc_wr_perm); } /* CCCD attribute metadata */ diff --git a/libraries/Bluefruit52Lib/src/BLEService.cpp b/libraries/Bluefruit52Lib/src/BLEService.cpp index 05bdd99cd..bbee03e9e 100644 --- a/libraries/Bluefruit52Lib/src/BLEService.cpp +++ b/libraries/Bluefruit52Lib/src/BLEService.cpp @@ -41,7 +41,8 @@ BLEService* BLEService::lastService = NULL; void BLEService::_init(void) { _handle = BLE_GATT_HANDLE_INVALID; - _permission = SECMODE_OPEN; + _read_perm = SECMODE_OPEN; + _write_perm = SECMODE_OPEN; } BLEService::BLEService(void) @@ -61,14 +62,16 @@ void BLEService::setUuid(BLEUuid bleuuid) uuid = bleuuid; } -void BLEService::setPermission(SecureMode_t permission) +void BLEService::setPermission(SecureMode_t read_perm, SecureMode_t write_perm) { - _permission = permission; + _read_perm = read_perm; + _write_perm = write_perm; } -SecureMode_t BLEService::getPermission(void) +void BLEService::getPermission(SecureMode_t* read_perm, SecureMode_t* write_perm) { - return _permission; + *read_perm = _read_perm; + *write_perm = _write_perm; } err_t BLEService::begin(void) diff --git a/libraries/Bluefruit52Lib/src/BLEService.h b/libraries/Bluefruit52Lib/src/BLEService.h index d7e02c1e7..4de334f55 100644 --- a/libraries/Bluefruit52Lib/src/BLEService.h +++ b/libraries/Bluefruit52Lib/src/BLEService.h @@ -43,7 +43,8 @@ class BLEService { protected: uint16_t _handle; // service gatt handle - SecureMode_t _permission; + SecureMode_t _read_perm; + SecureMode_t _write_perm; void _init(void); @@ -60,8 +61,8 @@ class BLEService void setUuid(BLEUuid bleuuid); - void setPermission(SecureMode_t permission); - SecureMode_t getPermission(void); + void setPermission(SecureMode_t read_perm, SecureMode_t write_perm); + void getPermission(SecureMode_t* read_perm, SecureMode_t* write_perm); virtual err_t begin(void); From e33fa240b5677ef016141564cebb9f3a7c4f5fdb Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 19 Mar 2020 23:44:47 +0700 Subject: [PATCH 69/74] revert ci to use latest arduino-cli, this will fails until arduino precompiled hanlding is fixed --- .github/workflows/githubci.yml | 7 +------ changelog.md | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/.github/workflows/githubci.yml b/.github/workflows/githubci.yml index ab4ed856d..6fd4944b4 100644 --- a/.github/workflows/githubci.yml +++ b/.github/workflows/githubci.yml @@ -35,12 +35,7 @@ jobs: mkdir $HOME/.arduino15/packages mkdir $HOME/Arduino mkdir $HOME/Arduino/libraries - # FIXME use arduino-cli 0.7.2 due to 0.9.0/IDE 1.8.2 precompiled hanlding broke nRFCypto - # https://github.com/arduino/arduino-builder/issues/353 - #curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh - wget https://github.com/arduino/arduino-cli/releases/download/0.7.2/arduino-cli_0.7.2_Linux_64bit.tar.gz - mkdir bin - tar -xf arduino-cli_0.7.2_Linux_64bit.tar.gz -C bin + curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh echo "::add-path::$GITHUB_WORKSPACE/bin" - name: Install BSP and Libraries diff --git a/changelog.md b/changelog.md index 01a9b9de0..c60a1c20c 100644 --- a/changelog.md +++ b/changelog.md @@ -2,7 +2,7 @@ ## 0.20.0 -This version implement comprehensive pairing with LESC and Legacy using dynamic & staic Passkey. +This version implement comprehensive LESC and Legacy pairing using dynamic & staic Passkey. - Support static passkey (Legacy only) - Support LESC on nRF52840 using hardware-accelerated ARM CryptoCell CC310 provided by [Adafruit_nRFCypto](https://github.com/adafruit/Adafruit_nRFCrypto), therefore nRFCrypto library must be installed From 4b63406bc6a4b394acaec71b1aa5ac4cf3b59c2f Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 11 Sep 2020 19:19:32 +0700 Subject: [PATCH 70/74] add Adafruit_nRFCrypto as submodule in libraries --- .gitmodules | 3 +++ libraries/Adafruit_nRFCrypto | 1 + 2 files changed, 4 insertions(+) create mode 160000 libraries/Adafruit_nRFCrypto diff --git a/.gitmodules b/.gitmodules index 8d325ddff..ef2d7254f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "cores/nRF5/TinyUSB/Adafruit_TinyUSB_ArduinoCore"] path = cores/nRF5/TinyUSB/Adafruit_TinyUSB_ArduinoCore url = https://github.com/adafruit/Adafruit_TinyUSB_ArduinoCore.git +[submodule "libraries/Adafruit_nRFCrypto"] + path = libraries/Adafruit_nRFCrypto + url = https://github.com/adafruit/Adafruit_nRFCrypto.git diff --git a/libraries/Adafruit_nRFCrypto b/libraries/Adafruit_nRFCrypto new file mode 160000 index 000000000..b12c46211 --- /dev/null +++ b/libraries/Adafruit_nRFCrypto @@ -0,0 +1 @@ +Subproject commit b12c46211c681f249aed89e455b7d813b2d4c312 From 6d9dde512061697b99497b508bff640fd24946d1 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 11 Sep 2020 20:14:08 +0700 Subject: [PATCH 71/74] update ci --- .github/workflows/githubci.yml | 2 +- libraries/Adafruit_nRFCrypto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/githubci.yml b/.github/workflows/githubci.yml index c8fdb2245..a7b897cda 100644 --- a/.github/workflows/githubci.yml +++ b/.github/workflows/githubci.yml @@ -54,7 +54,7 @@ jobs: ln -s $GITHUB_WORKSPACE $HOME/$BSP_PATH/$BSP_VERSION # Install library dependency - arduino-cli lib install "Adafruit AHRS" "Adafruit APDS9960 Library" "Adafruit BMP280 Library" "Adafruit Circuit Playground" "Adafruit EPD" "Adafruit GFX Library" "Adafruit HX8357 Library" "Adafruit ILI9341" "Adafruit LIS3MDL" "Adafruit LSM6DS" "Adafruit NeoPixel" "Adafruit NeoMatrix" "Adafruit nRFCrypto" "Adafruit Sensor Calibration" "Adafruit SHT31 Library" "Adafruit SSD1306" "Adafruit ST7735 and ST7789 Library" "SdFat - Adafruit Fork" + arduino-cli lib install "Adafruit AHRS" "Adafruit APDS9960 Library" "Adafruit Arcada Library" "Adafruit BMP280 Library" "Adafruit Circuit Playground" "Adafruit EPD" "Adafruit GFX Library" "Adafruit HX8357 Library" "Adafruit ILI9341" "Adafruit LIS3MDL" "Adafruit LSM6DS" "Adafruit NeoPixel" "Adafruit NeoMatrix" "Adafruit Sensor Calibration" "Adafruit SHT31 Library" "Adafruit SSD1306" "Adafruit ST7735 and ST7789 Library" "SdFat - Adafruit Fork" # TODO update to support MIDI version 5 later on arduino-cli lib install "MIDI Library"@4.3.1 diff --git a/libraries/Adafruit_nRFCrypto b/libraries/Adafruit_nRFCrypto index b12c46211..b6ae1bcc2 160000 --- a/libraries/Adafruit_nRFCrypto +++ b/libraries/Adafruit_nRFCrypto @@ -1 +1 @@ -Subproject commit b12c46211c681f249aed89e455b7d813b2d4c312 +Subproject commit b6ae1bcc274ae24efd98672f70d3efad28fd948e From 6a22fa5a9a7a9fd82e918e6d7075c29c10d62fb0 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 11 Sep 2020 22:21:56 +0700 Subject: [PATCH 72/74] fix ci build with 832 --- libraries/Adafruit_nRFCrypto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/Adafruit_nRFCrypto b/libraries/Adafruit_nRFCrypto index b6ae1bcc2..9b62a1b9a 160000 --- a/libraries/Adafruit_nRFCrypto +++ b/libraries/Adafruit_nRFCrypto @@ -1 +1 @@ -Subproject commit b6ae1bcc274ae24efd98672f70d3efad28fd948e +Subproject commit 9b62a1b9a36df5990868f3c058422b17c5de0447 From 96dc54aeb8a73c448662fdc1538ae66f50ddf5ed Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 11 Sep 2020 22:56:46 +0700 Subject: [PATCH 73/74] update nrf crypto --- libraries/Adafruit_nRFCrypto | 2 +- .../examples/Peripheral/clearbonds/clearbonds.ino | 6 +++++- .../Peripheral/pairing_passkey/pairing_passkey.ino | 10 +++++++--- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/libraries/Adafruit_nRFCrypto b/libraries/Adafruit_nRFCrypto index 9b62a1b9a..48b08a59d 160000 --- a/libraries/Adafruit_nRFCrypto +++ b/libraries/Adafruit_nRFCrypto @@ -1 +1 @@ -Subproject commit 9b62a1b9a36df5990868f3c058422b17c5de0447 +Subproject commit 48b08a59d11b167c6b3c124db043a6df81cf5007 diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/clearbonds/clearbonds.ino b/libraries/Bluefruit52Lib/examples/Peripheral/clearbonds/clearbonds.ino index 7e0c59b2b..5a9720556 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/clearbonds/clearbonds.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/clearbonds/clearbonds.ino @@ -22,7 +22,11 @@ void setup() { Serial.begin(115200); -// while ( !Serial ) delay(10); // for nrf52840 with native usb + +#if CFG_DEBUG + // Blocking wait for connection when debug mode is enabled via IDE + while ( !Serial ) yield(); +#endif Serial.println("Bluefruit52 Clear Bonds Example"); Serial.println("-------------------------------\n"); diff --git a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino index 5d7d870e3..b1f45758e 100644 --- a/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino +++ b/libraries/Bluefruit52Lib/examples/Peripheral/pairing_passkey/pairing_passkey.ino @@ -119,7 +119,8 @@ void setup() // Configure and Start BLE Uart Service // Set Permission to access BLE Uart is to require man-in-the-middle protection - // This will cause central to perform pairing with static PIN we set above + // This will cause central to perform pairing with a generated passkey, the passkey will + // be printed on display or Serial and wait for our input Serial.println("Configure BLE Uart to require man-in-the-middle protection for PIN pairing"); bleuart.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); bleuart.begin(); @@ -266,7 +267,7 @@ bool pairing_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6], bo uint32_t justReleased; do { - // Disconnected while waiting for input + // Peer is disconnected while waiting for input if ( !Bluefruit.connected(conn_handle) ) break; // time out @@ -286,7 +287,7 @@ bool pairing_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6], bo // wait until either button is pressed (30 seconds timeout) while( digitalRead(BUTTON_YES) && digitalRead(BUTTON_NO) ) { - // Disconnected while waiting for input + // Peer is disconnected while waiting for input if ( !Bluefruit.connected(conn_handle) ) break; // time out @@ -355,6 +356,9 @@ void disconnect_callback(uint16_t conn_handle, uint8_t reason) Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX); #ifdef USE_ARCADA + tft->fillScreen(ARCADA_BLACK); + tft->setTextSize(2); + tft->setCursor(0, 0); tft->println("Advertising ..."); #endif } From 3bb32231bd7e500e1135e94dd363a6e2c86c52e7 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 11 Sep 2020 23:02:23 +0700 Subject: [PATCH 74/74] update changelog --- changelog.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index 0256db717..d53ae2de3 100644 --- a/changelog.md +++ b/changelog.md @@ -1,11 +1,11 @@ # Adafruit nRF52 Arduino Core Changelog -## WIP +## 0.22.0 - WIP -This version implement comprehensive LESC and Legacy pairing using dynamic & staic Passkey. +This version implement comprehensive LESC and Legacy pairing using dynamic & static Passkey. - Support static passkey (Legacy only) -- Support LESC on nRF52840 using hardware-accelerated ARM CryptoCell CC310 provided by [Adafruit_nRFCypto](https://github.com/adafruit/Adafruit_nRFCrypto), therefore nRFCrypto library must be installed +- Support LESC on nRF52840 using hardware-accelerated ARM CryptoCell CC310 provided by [Adafruit_nRFCypto](https://github.com/adafruit/Adafruit_nRFCrypto). The library is included as submodule and released together with the BSP. - Rework bonding mechanism to use IRK for peer finding. It is advisable to run `clearbonds` example to clean up bond files of previous version ### BLESecurity