Skip to content

Commit

Permalink
Merge pull request #155 from particle-iot/feature/ble_encrypt
Browse files Browse the repository at this point in the history
Implement encryption for the BLE control request channel
  • Loading branch information
avtolstoy authored Jul 24, 2018
2 parents 910a744 + 9812f31 commit 50411e6
Show file tree
Hide file tree
Showing 29 changed files with 1,831 additions and 351 deletions.
24 changes: 23 additions & 1 deletion hal/inc/ble_hal.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,20 @@
// API version
#define BLE_API_VERSION 1

// Default maximum size of an ATT packet in bytes (ATT_MTU)
#define BLE_MIN_ATT_MTU_SIZE 23

// Size of the ATT opcode field in bytes
#define BLE_ATT_OPCODE_SIZE 1

// Size of the ATT handle field in bytes
#define BLE_ATT_HANDLE_SIZE 2

// Minimum and maximum number of bytes that can be sent in a single write command, read response,
// notification or indication packet
#define BLE_MIN_ATTR_VALUE_PACKET_SIZE (BLE_MIN_ATT_MTU_SIZE - BLE_ATT_OPCODE_SIZE - BLE_ATT_HANDLE_SIZE)
#define BLE_MAX_ATTR_VALUE_PACKET_SIZE (BLE_MAX_ATT_MTU_SIZE - BLE_ATT_OPCODE_SIZE - BLE_ATT_HANDLE_SIZE)

#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -101,6 +115,13 @@ typedef struct ble_service {
uint16_t char_count;
} ble_service;

// Manufacturer-specific data
typedef struct ble_manuf_data {
uint16_t company_id;
uint16_t size;
const char* data;
} ble_manuf_data;

// BLE_EVENT_CONNECTED event data
typedef struct ble_connected_event_data {
uint16_t conn_handle;
Expand Down Expand Up @@ -146,14 +167,15 @@ typedef struct ble_profile {
uint16_t service_count;
ble_service* services;
const char* device_name;
const ble_manuf_data* manuf_data;
ble_event_callback callback;
void* user_data;
} ble_profile;

// Connection parameters
typedef struct ble_conn_param {
uint16_t version; // API version
uint16_t max_char_value_size;
uint16_t att_mtu_size; // Maximum size of an ATT packet (ATT_MTU)
} ble_conn_param;

// Characteristic parameters
Expand Down
9 changes: 9 additions & 0 deletions hal/inc/deviceid_hal.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@
// Size of the device's serial number
#define HAL_DEVICE_SERIAL_NUMBER_SIZE 15

// Size of the device secret data
#define HAL_DEVICE_SECRET_SIZE 32

#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -74,6 +77,12 @@ void HAL_save_device_id(uint32_t offset);
*/
int hal_get_device_serial_number(char* str, size_t size, void* reserved);

/**
* Get the device secret data.
*/
// TODO: Move this function to an appropriate module
int hal_get_device_secret(char* data, size_t size, void* reserved);

#ifdef __cplusplus
}
#endif
Expand Down
15 changes: 2 additions & 13 deletions hal/src/nRF52840/ble_hal_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,6 @@
#error "NRF_SDH_BLE_GATT_MAX_MTU_SIZE is not defined"
#endif

// TODO: Move to an appropriate platform header
#ifndef BLE_ENABLED
#define BLE_ENABLED 1
#endif

// Invalid connection handle
// TODO: Prefix all BLE HAL definitions with "hal_"
#define BLE_INVALID_CONN_HANDLE BLE_CONN_HANDLE_INVALID
Expand All @@ -47,11 +42,5 @@
// Maximum number of characteristics per service
#define BLE_MAX_CHAR_COUNT 4

// Size of the ATT opcode field in bytes
#define BLE_ATT_OPCODE_SIZE 1

// Size of the ATT handle field in bytes
#define BLE_ATT_HANDLE_SIZE 2

// Maximum size of an attribute's value in bytes
#define BLE_MAX_ATTR_VALUE_SIZE (NRF_SDH_BLE_GATT_MAX_MTU_SIZE - BLE_ATT_OPCODE_SIZE - BLE_ATT_HANDLE_SIZE)
// Maximum supported size of an ATT packet in bytes (ATT_MTU)
#define BLE_MAX_ATT_MTU_SIZE NRF_SDH_BLE_GATT_MAX_MTU_SIZE
37 changes: 36 additions & 1 deletion hal/src/nRF52840/deviceid_hal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
#include "deviceid_hal.h"
#include "exflash_hal.h"
#include "str_util.h"
#include "random.h"
#include "dct.h"

#include "nrf52840.h"

#include <algorithm>
Expand All @@ -28,6 +31,9 @@ using namespace particle;

const uint32_t DEVICE_ID_PREFIX = 0x68ce0fe0;

const uintptr_t SERIAL_NUMBER_OTP_ADDRESS = 0x00000000;
const uintptr_t DEVICE_SECRET_OTP_ADDRESS = 0x00000010;

} // namespace

unsigned HAL_device_ID(uint8_t* dest, unsigned destLen)
Expand All @@ -54,7 +60,7 @@ int hal_get_device_serial_number(char* str, size_t size, void* reserved)
{
char serial[HAL_DEVICE_SERIAL_NUMBER_SIZE] = {};

int r = hal_exflash_read_special(HAL_EXFLASH_SPECIAL_SECTOR_OTP, 0,
int r = hal_exflash_read_special(HAL_EXFLASH_SPECIAL_SECTOR_OTP, SERIAL_NUMBER_OTP_ADDRESS,
(uint8_t*)serial, HAL_DEVICE_SERIAL_NUMBER_SIZE);

if (r != 0 || !isPrintable(serial, sizeof(serial))) {
Expand All @@ -69,3 +75,32 @@ int hal_get_device_serial_number(char* str, size_t size, void* reserved)
}
return HAL_DEVICE_SERIAL_NUMBER_SIZE;
}

int hal_get_device_secret(char* data, size_t size, void* reserved)
{
// Check if the device secret data is initialized in the DCT
char secret[HAL_DEVICE_SECRET_SIZE] = {};
static_assert(sizeof(secret) == DCT_DEVICE_SECRET_SIZE, "");
int ret = dct_read_app_data_copy(DCT_DEVICE_SECRET_OFFSET, secret, sizeof(secret));
if (ret < 0) {
return ret;
}
if (!isPrintable(secret, sizeof(secret))) {
// Check the OTP memory
ret = hal_exflash_read_special(HAL_EXFLASH_SPECIAL_SECTOR_OTP, DEVICE_SECRET_OTP_ADDRESS, (uint8_t*)secret, sizeof(secret));
if (ret < 0) {
return ret;
}
if (!isPrintable(secret, sizeof(secret))) {
// Generate random data
Random().genBase32(secret, sizeof(secret));
}
// Update the DCT
ret = dct_write_app_data(secret, DCT_DEVICE_SECRET_OFFSET, sizeof(secret));
if (ret < 0) {
return ret;
}
}
memcpy(data, secret, std::min(size, sizeof(secret)));
return HAL_DEVICE_SECRET_SIZE;
}
21 changes: 15 additions & 6 deletions hal/src/xenon/ble_hal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,21 +271,30 @@ void processGattEvent(nrf_ble_gatt_t* gatt, const nrf_ble_gatt_evt_t* event) {

int halError(uint32_t error) {
switch (error) {
case NRF_ERROR_INVALID_STATE:
return BLE_ERROR_INVALID_STATE;
case NRF_ERROR_NO_MEM:
return BLE_ERROR_NO_MEMORY;
default:
return BLE_ERROR_UNKNOWN;
}
}

int initAdvert() {
int initAdvert(const ble_manuf_data* halManufData) {
// Service UUIDs
ble_uuid_t svcUuids[BLE_MAX_SERVICE_COUNT] = {};
for (size_t i = 0; i < g_profile.serviceCount; ++i) {
svcUuids[i] = g_profile.services[i].uuid;
}
// Initialize the advertising module
ble_advertising_init_t init = {};
ble_advdata_manuf_data_t manufData = {};
if (halManufData) {
manufData.company_identifier = halManufData->company_id;
manufData.data.p_data = (uint8_t*)halManufData->data;
manufData.data.size = halManufData->size;
init.advdata.p_manuf_specific_data = &manufData;
}
init.advdata.name_type = BLE_ADVDATA_FULL_NAME;
init.advdata.include_appearance = false;
init.advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
Expand Down Expand Up @@ -340,7 +349,7 @@ int initTxChar(uint16_t serviceHandle, ble_char* halChar, Char* chr) {
ble_gatts_attr_t attr = {};
attr.p_uuid = &chr->uuid;
attr.p_attr_md = &attrMd;
attr.max_len = BLE_MAX_ATTR_VALUE_SIZE;
attr.max_len = BLE_MAX_ATTR_VALUE_PACKET_SIZE;
const uint32_t ret = sd_ble_gatts_characteristic_add(serviceHandle, &charMd, &attr, &chr->handles);
if (ret != NRF_SUCCESS) {
LOG(ERROR, "sd_ble_gatts_characteristic_add() failed: %u", (unsigned)ret);
Expand Down Expand Up @@ -371,7 +380,7 @@ int initRxChar(uint16_t serviceHandle, ble_char* halChar, Char* chr) {
ble_gatts_attr_t attr = {};
attr.p_uuid = &chr->uuid;
attr.p_attr_md = &attrMd;
attr.max_len = BLE_MAX_ATTR_VALUE_SIZE;
attr.max_len = BLE_MAX_ATTR_VALUE_PACKET_SIZE;
const uint32_t ret = sd_ble_gatts_characteristic_add(serviceHandle, &charMd, &attr, &chr->handles);
if (ret != NRF_SUCCESS) {
LOG(ERROR, "sd_ble_gatts_characteristic_add() failed: %u", (unsigned)ret);
Expand Down Expand Up @@ -581,7 +590,7 @@ int ble_init_profile(ble_profile* profile, void* reserved) {
LOG(ERROR, "Unable to initialize profile");
return ret;
}
ret = initAdvert();
ret = initAdvert(profile->manuf_data);
if (ret != 0) {
LOG(ERROR, "Unable to initialize advertising module");
return ret;
Expand Down Expand Up @@ -673,11 +682,11 @@ int ble_get_conn_param(uint16_t conn_handle, ble_conn_param* param, void* reserv
return BLE_ERROR_INVALID_PARAM;
}
const uint16_t mtu = nrf_ble_gatt_eff_mtu_get(&g_gatt, conn_handle);
if (mtu == 0 || mtu <= BLE_ATT_OPCODE_SIZE + BLE_ATT_HANDLE_SIZE) {
if (mtu < BLE_MIN_ATT_MTU_SIZE) {
LOG(ERROR, "nrf_ble_gatt_eff_mtu_get() failed");
return BLE_ERROR_UNKNOWN;
}
param->max_char_value_size = mtu - BLE_ATT_OPCODE_SIZE - BLE_ATT_HANDLE_SIZE;
param->att_mtu_size = mtu;
return 0;
}

Expand Down
2 changes: 1 addition & 1 deletion hal/src/xenon/hal_platform_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

#define HAL_IPv6 (1)

#define HAL_PLATFORM_BLE (1)
#define HAL_PLATFORM_BLE (1)

/* XXX: */
#define HAL_PLATFORM_DEFAULT_CLOUD_KEEPALIVE_INTERVAL (20000)
Expand Down
10 changes: 7 additions & 3 deletions platform/MCU/nRF52840/inc/dct.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ typedef struct __attribute__((packed)) application_dct {
led_config_t led_mirror[4]; // LED mirroring configuration, to be used by bootloader
uint8_t led_theme[64]; // LED signaling theme
eap_config_t eap_config; // WLAN EAP settings
uint8_t reserved2[272];
uint8_t device_secret[32]; // Device secret data (aka "mobile secret")
uint8_t reserved2[240];
// safe to add more data here or use up some of the reserved space to keep the end where it is
uint8_t end[0];
} application_dct_t;
Expand Down Expand Up @@ -135,6 +136,7 @@ typedef struct __attribute__((packed)) application_dct {
#define DCT_LED_MIRROR_OFFSET (offsetof(application_dct_t, led_mirror))
#define DCT_LED_THEME_OFFSET (offsetof(application_dct_t, led_theme))
#define DCT_EAP_CONFIG_OFFSET (offsetof(application_dct_t, eap_config))
#define DCT_DEVICE_SECRET_OFFSET (offsetof(application_dct_t, device_secret))

#define DCT_SYSTEM_FLAGS_SIZE (sizeof(application_dct_t::system_flags))
#define DCT_DEVICE_PRIVATE_KEY_SIZE (sizeof(application_dct_t::device_private_key))
Expand Down Expand Up @@ -162,6 +164,7 @@ typedef struct __attribute__((packed)) application_dct {
#define DCT_LED_MIRROR_SIZE (sizeof(application_dct_t::led_mirror))
#define DCT_LED_THEME_SIZE (sizeof(application_dct_t::led_theme))
#define DCT_EAP_CONFIG_SIZE (sizeof(application_dct_t::eap_config))
#define DCT_DEVICE_SECRET_SIZE (sizeof(application_dct_t::device_secret))

#define STATIC_ASSERT_DCT_OFFSET(field, expected) PARTICLE_STATIC_ASSERT( dct_##field, offsetof(application_dct_t, field)==expected)
#define STATIC_ASSERT_FLAGS_OFFSET(field, expected) PARTICLE_STATIC_ASSERT( dct_sysflag_##field, offsetof(platform_system_flags_t, field)==expected)
Expand Down Expand Up @@ -199,8 +202,9 @@ STATIC_ASSERT_DCT_OFFSET(mode_button_mirror, 3631 /* 3630 + 1 */);
STATIC_ASSERT_DCT_OFFSET(led_mirror, 3663 /* 3631 + 32 */);
STATIC_ASSERT_DCT_OFFSET(led_theme, 3759 /* 3663 + 24 * 4 */);
STATIC_ASSERT_DCT_OFFSET(eap_config, 3823 /* 3759 + 64 */);
STATIC_ASSERT_DCT_OFFSET(reserved2, 8119 /* 3823 + (196 + 4*1024 + 4) */);
STATIC_ASSERT_DCT_OFFSET(end, 8391 /* 8119 + 272 */);
STATIC_ASSERT_DCT_OFFSET(device_secret, 8119 /* 3823 + (196 + 4*1024 + 4) */);
STATIC_ASSERT_DCT_OFFSET(reserved2, 8151 /* 8119 + 32 */);
STATIC_ASSERT_DCT_OFFSET(end, 8391 /* 8151 + 240 */);

STATIC_ASSERT_FLAGS_OFFSET(Bootloader_Version_SysFlag, 4);
STATIC_ASSERT_FLAGS_OFFSET(NVMEM_SPARK_Reset_SysFlag, 6);
Expand Down
2 changes: 1 addition & 1 deletion proto
Submodule proto updated from 7598b3 to f58553
59 changes: 59 additions & 0 deletions services/inc/allocator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2018 Particle Industries, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

#include <cstdlib>

namespace particle {

// Abstract allocator
class SimpleAllocator {
public:
virtual ~SimpleAllocator() = default;

virtual void* alloc(size_t size) = 0;
virtual void free(void* ptr) = 0;
};

class Allocator: public SimpleAllocator {
public:
virtual void* realloc(void* ptr, size_t size) = 0;
};

// Allocator interface for malloc()
class HeapAllocator: public Allocator {
public:
virtual void* alloc(size_t size) override {
return ::malloc(size);
}

virtual void* realloc(void* ptr, size_t size) override {
return ::realloc(ptr, size);
}

virtual void free(void* ptr) override {
::free(ptr);
}

static HeapAllocator* instance() {
static HeapAllocator alloc;
return &alloc;
}
};

} // particle
Loading

0 comments on commit 50411e6

Please sign in to comment.