Skip to content

Commit

Permalink
[nRF52] 'secure' BLE DFU logic [skip ci]
Browse files Browse the repository at this point in the history
  • Loading branch information
lyusupov committed Jul 25, 2024
1 parent 712ddca commit 149cdbc
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 5 deletions.
112 changes: 111 additions & 1 deletion software/firmware/source/SoftRF/src/platform/bluetooth/Bluefruit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,110 @@ bool BLESensBox::notify_sys(uint8_t status)
return _sensbox_sys.notify(&data, sizeof(sensbox_system_t)) > 0;
}

const uint16_t UUID16_SVC_DFU_OTA = 0xFE59;

const uint8_t UUID128_CHR_DFU_CONTROL[16] = {0x50, 0xEA, 0xDA, 0x30, 0x88, 0x83, 0xB8, 0x9F,
0x60, 0x4F, 0x15, 0xF3, 0x03, 0x00, 0xC9, 0x8E};

extern "C" void bootloader_util_app_start(uint32_t start_addr);

static uint16_t crc16(const uint8_t *data_p, uint8_t length)
{
uint8_t x;
uint16_t crc = 0xFFFF;

while (length--) {
x = crc >> 8 ^ *data_p++;
x ^= x >> 4;
crc = (crc << 8) ^ ((uint16_t)(x << 12)) ^ ((uint16_t)(x << 5)) ^ ((uint16_t)x);
}
return crc;
}

static void bledfu_control_wr_authorize_cb(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_write_t *request)
{
if ((request->handle == chr->handles().value_handle) && (request->op != BLE_GATTS_OP_PREP_WRITE_REQ) &&
(request->op != BLE_GATTS_OP_EXEC_WRITE_REQ_NOW) && (request->op != BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)) {
BLEConnection *conn = Bluefruit.Connection(conn_hdl);

ble_gatts_rw_authorize_reply_params_t reply = {.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE};

if (!chr->indicateEnabled(conn_hdl)) {
reply.params.write.gatt_status = BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR;
sd_ble_gatts_rw_authorize_reply(conn_hdl, &reply);
return;
}

reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
sd_ble_gatts_rw_authorize_reply(conn_hdl, &reply);

enum { START_DFU = 1 };
if (request->data[0] == START_DFU) {
// Peer data information so that bootloader could re-connect after reboot
typedef struct {
ble_gap_addr_t addr;
ble_gap_irk_t irk;
ble_gap_enc_key_t enc_key;
uint8_t sys_attr[8];
uint16_t crc16;
} peer_data_t;

VERIFY_STATIC(offsetof(peer_data_t, crc16) == 60);

/* Save Peer data
* Peer data address is defined in bootloader linker @0x20007F80
* - If bonded : save Security information
* - Otherwise : save Address for direct advertising
*
* TODO may force bonded only for security reason
*/
peer_data_t *peer_data = (peer_data_t *)(0x20007F80UL);
varclr(peer_data);

// Get CCCD
uint16_t sysattr_len = sizeof(peer_data->sys_attr);
sd_ble_gatts_sys_attr_get(conn_hdl, peer_data->sys_attr, &sysattr_len, BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS);

// Get Bond Data or using Address if not bonded
peer_data->addr = conn->getPeerAddr();

if (conn->secured()) {
bond_keys_t bkeys;
if (conn->loadBondKey(&bkeys)) {
peer_data->addr = bkeys.peer_id.id_addr_info;
peer_data->irk = bkeys.peer_id.id_info;
peer_data->enc_key = bkeys.own_enc;
}
}

// Calculate crc
peer_data->crc16 = crc16((uint8_t *)peer_data, offsetof(peer_data_t, crc16));

// Initiate DFU Sequence and reboot into DFU OTA mode
Bluefruit.Advertising.restartOnDisconnect(false);
conn->disconnect();

NRF_POWER->GPREGRET = 0xB1;
NVIC_SystemReset();
}
}
}

BLEDfuSecure::BLEDfuSecure(void) : BLEService(UUID16_SVC_DFU_OTA), _chr_control(UUID128_CHR_DFU_CONTROL) {}

err_t BLEDfuSecure::begin(void)
{
// Invoke base class begin()
VERIFY_STATUS(BLEService::begin());

_chr_control.setProperties(CHR_PROPS_WRITE | CHR_PROPS_INDICATE);
_chr_control.setMaxLen(23);
_chr_control.setWriteAuthorizeCallback(bledfu_control_wr_authorize_cb);
VERIFY_STATUS(_chr_control.begin());

return ERROR_NONE;
}

static unsigned long BLE_Notify_TimeMarker = 0;
static unsigned long BLE_SensBox_TimeMarker = 0;

Expand All @@ -193,6 +297,7 @@ static unsigned long BLE_SensBox_TimeMarker = 0;

// BLE Service
BLEDfu bledfu; // OTA DFU service
BLEDfuSecure bledfusecure;
BLEDis bledis; // device information
BLEUart_HM10 bleuart_HM10; // TI UART over BLE
#if !defined(EXCLUDE_NUS)
Expand Down Expand Up @@ -362,7 +467,12 @@ void nRF52_Bluetooth_setup()
Bluefruit.Periph.setDisconnectCallback(disconnect_callback);

// To be consistent OTA DFU should be added first if it exists
bledfu.begin();
if (hw_info.model == SOFTRF_MODEL_CARD) {
bledfusecure.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM);
bledfusecure.begin();
} else {
bledfu.begin();
}

// Configure and Start Device Information Service
bledis.setManufacturer(nRF52_Device_Manufacturer);
Expand Down
11 changes: 11 additions & 0 deletions software/firmware/source/SoftRF/src/platform/bluetooth/Bluefruit.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,15 @@ typedef struct {

#define isTimeToSensBox() (millis() - BLE_SensBox_TimeMarker > 500) /* 2 Hz */

class BLEDfuSecure : public BLEService
{
protected:
BLECharacteristic _chr_control;

public:
BLEDfuSecure(void);

virtual err_t begin(void);
};

extern IODev_ops_t nRF52_Bluetooth_ops;
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
#define SOC_GPIO_PIN_GNSS_T1000_TX _PINNUM(0, 13) // P0.13

#define SOC_GPIO_PIN_GNSS_T1000_PPS SOC_UNUSED_PIN
#define SOC_GPIO_PIN_GNSS_T1000_IRQ _PINNUM(1, 12) // P1.12
#define SOC_GPIO_PIN_GNSS_T1000_RST _PINNUM(1, 15) // P1.15 active HIGH
#define SOC_GPIO_PIN_GNSS_T1000_EN _PINNUM(1, 11) // P1.11 active HIGH
#define SOC_GPIO_PIN_GNSS_T1000_RST _PINNUM(1, 15) // P1.15 active HIGH
#define SOC_GPIO_PIN_GNSS_T1000_VRTC _PINNUM(0, 8) // P0.08
#define SOC_GPIO_PIN_GNSS_T1000_SINT _PINNUM(1, 12) // P1.12
#define SOC_GPIO_PIN_GNSS_T1000_RINT _PINNUM(0, 15) // P0.15

/* SPI */
#define SOC_GPIO_PIN_T1000_MOSI _PINNUM(1, 9) // P1.09
Expand Down
27 changes: 25 additions & 2 deletions software/firmware/source/SoftRF/src/platform/nRF52.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,9 @@ static void nRF52_setup()
Wire.end();

#if !defined(EXCLUDE_IMU)
pinMode(SOC_GPIO_PIN_T1000_ACC_EN, INPUT_PULLUP);
delay(200);

#if !defined(ARDUINO_ARCH_MBED)
Wire.setPins(SOC_GPIO_PIN_T1000_SDA, SOC_GPIO_PIN_T1000_SCL);
#endif /* ARDUINO_ARCH_MBED */
Expand All @@ -713,6 +716,7 @@ static void nRF52_setup()
nRF52_Device_Model = "Card Edition";
}
Wire.end();
pinMode(SOC_GPIO_PIN_T1000_ACC_EN, INPUT);
#endif /* EXCLUDE_IMU */
}
#endif /* EXCLUDE_PMU */
Expand Down Expand Up @@ -750,6 +754,15 @@ static void nRF52_setup()
case NRF52_LILYGO_TULTIMA:
/* TBD */
break;

case NRF52_SEEED_T1000:
pinMode(SOC_GPIO_PIN_T1000_3V3_EN, OUTPUT);
digitalWrite(SOC_GPIO_PIN_T1000_3V3_EN, HIGH);

pinMode(SOC_GPIO_PIN_T1000_BUZZER_EN, OUTPUT);
digitalWrite(SOC_GPIO_PIN_T1000_BUZZER_EN, HIGH);
break;

case NRF52_LILYGO_TECHO_REV_0:
case NRF52_LILYGO_TECHO_REV_1:
case NRF52_LILYGO_TECHO_REV_2:
Expand Down Expand Up @@ -896,11 +909,21 @@ static void nRF52_setup()
break;

case NRF52_SEEED_T1000:
digitalWrite(SOC_GPIO_PIN_GNSS_T1000_RST, LOW);
pinMode(SOC_GPIO_PIN_GNSS_T1000_RST, OUTPUT);
digitalWrite(SOC_GPIO_PIN_GNSS_T1000_EN, HIGH);
pinMode(SOC_GPIO_PIN_GNSS_T1000_EN, OUTPUT);

pinMode(SOC_GPIO_PIN_GNSS_T1000_VRTC, OUTPUT);
digitalWrite(SOC_GPIO_PIN_GNSS_T1000_VRTC, HIGH);

digitalWrite(SOC_GPIO_PIN_GNSS_T1000_RST, LOW);
pinMode(SOC_GPIO_PIN_GNSS_T1000_RST, OUTPUT);

pinMode(SOC_GPIO_PIN_GNSS_T1000_SINT, OUTPUT);
digitalWrite(SOC_GPIO_PIN_GNSS_T1000_SINT, HIGH);

pinMode(SOC_GPIO_PIN_GNSS_T1000_RINT, OUTPUT);
digitalWrite(SOC_GPIO_PIN_GNSS_T1000_RINT, LOW);

pinMode(SOC_GPIO_LED_T1000_GREEN, OUTPUT);
ledOn (SOC_GPIO_LED_T1000_GREEN);

Expand Down

0 comments on commit 149cdbc

Please sign in to comment.