microbit: Alpha version of standard BLE MITM passkey security
- refactored BLE funcitonality into BLEManager class. - added security requirements standard BLE profile services. - updated bluezone pairing process to use BLE passkey exchange.master
parent
79c739674c
commit
ac381fa5dc
|
@ -136,11 +136,6 @@ class MicroBit
|
|||
*/
|
||||
void init();
|
||||
|
||||
/**
|
||||
* Derives the friendly name for this device, autogenerated from our hardware Device ID.
|
||||
*/
|
||||
void deriveName();
|
||||
|
||||
/**
|
||||
* Return the friendly name for this device.
|
||||
*
|
||||
|
|
|
@ -33,6 +33,10 @@
|
|||
#include "MicroBitTemperatureService.h"
|
||||
#include "ExternalEvents.h"
|
||||
|
||||
#define MICROBIT_BLE_PAIR_REQUEST 0x01
|
||||
#define MICROBIT_BLE_PAIR_COMPLETE 0x02
|
||||
#define MICROBIT_BLE_PAIR_SUCCESSFUL 0x04
|
||||
|
||||
/**
|
||||
* Class definition for the MicroBitBLEManager.
|
||||
*
|
||||
|
@ -68,7 +72,7 @@ class MicroBitBLEManager
|
|||
void init(ManagedString deviceName, ManagedString serialNumber);
|
||||
|
||||
/**
|
||||
* Enter BLUEZOE mode. This is mode is called to initiate pairing, and to enable FOTA programming
|
||||
* Enter BLUEZONE mode. This is mode is called to initiate pairing, and to enable FOTA programming
|
||||
* of the micro:bit in cases where BLE is disabled during normal operation.
|
||||
*
|
||||
* @param display a MicroBitDisplay to use when displaying pairing information.
|
||||
|
@ -81,6 +85,29 @@ class MicroBitBLEManager
|
|||
* this callback to restart advertising.
|
||||
*/
|
||||
void onDisconnectionCallback();
|
||||
|
||||
/**
|
||||
* Displays the device's ID code as a histogram on the LED matrix display.
|
||||
*/
|
||||
void showNameHistogram(MicroBitDisplay &display);
|
||||
|
||||
/**
|
||||
* A request to pair has been received from a BLE device.
|
||||
* If we're in BLUEZONE mode, display the passkey to the user.
|
||||
*/
|
||||
void pairingRequested(ManagedString passKey);
|
||||
|
||||
/**
|
||||
* A pairing request has been sucesfully completed.
|
||||
* If we're in BLUEZONE mode, display feedback to the user.
|
||||
*/
|
||||
void pairingComplete(bool success);
|
||||
|
||||
private:
|
||||
int pairingStatus;
|
||||
ManagedString passKey;
|
||||
ManagedString deviceName;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
#include "MicroBit.h"
|
||||
|
||||
char MICROBIT_BLE_DEVICE_NAME[] = "BBC micro:bit [xxxxx]";
|
||||
|
||||
|
||||
/**
|
||||
* custom function for panic for malloc & new due to scoping issue.
|
||||
*/
|
||||
|
@ -90,9 +87,6 @@ void MicroBit::init()
|
|||
// Seed our random number generator
|
||||
seedRandom();
|
||||
|
||||
// Generate the name for our device.
|
||||
this->deriveName();
|
||||
|
||||
#if CONFIG_ENABLED(MICROBIT_BLE_ENABLED)
|
||||
// Start the BLE stack.
|
||||
bleManager.init(this->getName(), this->getSerial());
|
||||
|
@ -104,10 +98,13 @@ void MicroBit::init()
|
|||
}
|
||||
|
||||
/**
|
||||
* Derives the friendly name for this device, autogenerated from our hardware Device ID.
|
||||
* Return the friendly name for this device.
|
||||
*
|
||||
* @return A string representing the friendly name of this device.
|
||||
*/
|
||||
void MicroBit::deriveName()
|
||||
ManagedString MicroBit::getName()
|
||||
{
|
||||
char nameBuffer[MICROBIT_NAME_LENGTH];
|
||||
const uint8_t codebook[MICROBIT_NAME_LENGTH][MICROBIT_NAME_CODE_LETTERS] =
|
||||
{
|
||||
{'z', 'v', 'g', 'p', 't'},
|
||||
|
@ -117,13 +114,12 @@ void MicroBit::deriveName()
|
|||
{'z', 'v', 'g', 'p', 't'}
|
||||
};
|
||||
|
||||
char *name = MICROBIT_BLE_DEVICE_NAME+15;
|
||||
|
||||
// We count right to left, so fast forward the pointer.
|
||||
// We count right to left, so create a pointer to the end of the buffer.
|
||||
char *name = nameBuffer;
|
||||
name += MICROBIT_NAME_LENGTH;
|
||||
|
||||
// Derive our name from the nrf51822's unique ID.
|
||||
uint32_t n = NRF_FICR->DEVICEID[1];
|
||||
|
||||
int ld = 1;
|
||||
int d = MICROBIT_NAME_CODE_LETTERS;
|
||||
int h;
|
||||
|
@ -136,16 +132,8 @@ void MicroBit::deriveName()
|
|||
ld *= MICROBIT_NAME_CODE_LETTERS;
|
||||
*--name = codebook[i][h];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the friendly name for this device.
|
||||
*
|
||||
* @return A string representing the friendly name of this device.
|
||||
*/
|
||||
ManagedString MicroBit::getName()
|
||||
{
|
||||
return ManagedString(MICROBIT_BLE_DEVICE_NAME+15, MICROBIT_NAME_LENGTH);
|
||||
return ManagedString(nameBuffer, MICROBIT_NAME_LENGTH);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -29,7 +29,11 @@ MicroBitAccelerometerService::MicroBitAccelerometerService(BLEDevice &_ble) :
|
|||
accelerometerDataCharacteristicBuffer[1] = 0;
|
||||
accelerometerDataCharacteristicBuffer[2] = 0;
|
||||
accelerometerPeriodCharacteristicBuffer = uBit.accelerometer.getPeriod();
|
||||
|
||||
|
||||
// Set default security requirements
|
||||
accelerometerDataCharacteristic.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM);
|
||||
accelerometerPeriodCharacteristic.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM);
|
||||
|
||||
GattCharacteristic *characteristics[] = {&accelerometerDataCharacteristic, &accelerometerPeriodCharacteristic};
|
||||
GattService service(MicroBitAccelerometerServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
|
||||
|
||||
|
|
|
@ -33,35 +33,20 @@ static void passkeyDisplayCallback(Gap::Handle_t handle, const SecurityManager::
|
|||
{
|
||||
(void) handle; /* -Wunused-param */
|
||||
|
||||
printf("Input passKey: ");
|
||||
for (unsigned i = 0; i < Gap::ADDR_LEN; i++) {
|
||||
printf("%c", passkey[i]);
|
||||
}
|
||||
printf("\r\n");
|
||||
ManagedString passKey((const char *)passkey, SecurityManager::PASSKEY_LEN);
|
||||
|
||||
if (manager)
|
||||
manager->pairingRequested(passKey);
|
||||
}
|
||||
|
||||
static void securitySetupCompletedCallback(Gap::Handle_t handle, SecurityManager::SecurityCompletionStatus_t status)
|
||||
{
|
||||
(void) handle; /* -Wunused-param */
|
||||
|
||||
if (status == SecurityManager::SEC_STATUS_SUCCESS) {
|
||||
printf("Security success %d\r\n", status);
|
||||
} else {
|
||||
printf("Security failed %d\r\n", status);
|
||||
}
|
||||
if (manager)
|
||||
manager->pairingComplete(status == SecurityManager::SEC_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
static void securitySetupInitiatedCallback(Gap::Handle_t handle, bool allowBonding, bool requireMITM, SecurityManager::SecurityIOCapabilities_t iocaps)
|
||||
{
|
||||
(void) handle; /* -Wunused-param */
|
||||
(void) allowBonding; /* -Wunused-param */
|
||||
(void) requireMITM; /* -Wunused-param */
|
||||
(void) iocaps; /* -Wunused-param */
|
||||
|
||||
printf("Security setup initiated\r\n");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
|
@ -72,7 +57,9 @@ static void securitySetupInitiatedCallback(Gap::Handle_t handle, bool allowBondi
|
|||
*/
|
||||
MicroBitBLEManager::MicroBitBLEManager()
|
||||
{
|
||||
manager = this;
|
||||
this->ble = NULL;
|
||||
this->pairingStatus = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -99,6 +86,12 @@ void MicroBitBLEManager::onDisconnectionCallback()
|
|||
*/
|
||||
void MicroBitBLEManager::init(ManagedString deviceName, ManagedString serialNumber)
|
||||
{
|
||||
ManagedString prefix("BBC micro:bit [");
|
||||
ManagedString postfix("]");
|
||||
ManagedString BLEName = prefix + deviceName + postfix;
|
||||
|
||||
this->deviceName = deviceName;
|
||||
|
||||
// Start the BLE stack.
|
||||
ble = new BLEDevice();
|
||||
ble->init();
|
||||
|
@ -107,7 +100,6 @@ void MicroBitBLEManager::init(ManagedString deviceName, ManagedString serialNumb
|
|||
ble->onDisconnection(bleDisconnectionCallback);
|
||||
|
||||
// Setup our security requirements.
|
||||
ble->securityManager().onSecuritySetupInitiated(securitySetupInitiatedCallback);
|
||||
ble->securityManager().onPasskeyDisplay(passkeyDisplayCallback);
|
||||
ble->securityManager().onSecuritySetupCompleted(securitySetupCompletedCallback);
|
||||
ble->securityManager().init(MICROBIT_BLE_ENABLE_BONDING, MICROBIT_BLE_REQUIRE_MITM, SecurityManager::IO_CAPS_DISPLAY_ONLY);
|
||||
|
@ -159,20 +151,96 @@ void MicroBitBLEManager::init(ManagedString deviceName, ManagedString serialNumb
|
|||
|
||||
// Setup advertising.
|
||||
ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
|
||||
ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)deviceName.toCharArray(), deviceName.length());
|
||||
ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)BLEName.toCharArray(), BLEName.length());
|
||||
ble->setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
|
||||
ble->setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(200));
|
||||
ble->startAdvertising();
|
||||
}
|
||||
|
||||
/**
|
||||
* A request to pair has been received from a BLE device.
|
||||
* If we're in BLUEZONE mode, display the passkey to the user.
|
||||
*/
|
||||
void MicroBitBLEManager::pairingRequested(ManagedString passKey)
|
||||
{
|
||||
this->passKey = passKey;
|
||||
this->pairingStatus = MICROBIT_BLE_PAIR_REQUEST;
|
||||
}
|
||||
|
||||
/**
|
||||
* A pairing request has been sucesfully completed.
|
||||
* If we're in BLUEZONE mode, display feedback to the user.
|
||||
*/
|
||||
void MicroBitBLEManager::pairingComplete(bool success)
|
||||
{
|
||||
this->pairingStatus &= ~MICROBIT_BLE_PAIR_REQUEST;
|
||||
this->pairingStatus |= MICROBIT_BLE_PAIR_COMPLETE;
|
||||
|
||||
if(success)
|
||||
this->pairingStatus |= MICROBIT_BLE_PAIR_SUCCESSFUL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter BLUEZONE mode. This is mode is called to initiate pairing, and to enable FOTA programming
|
||||
* of the micro:bit in cases where BLE is disabled during normal operation.
|
||||
*/
|
||||
void MicroBitBLEManager::bluezone(MicroBitDisplay &display)
|
||||
{
|
||||
// TODO:
|
||||
while(1);
|
||||
{
|
||||
// Stop any running animations on the display
|
||||
display.stopAnimation();
|
||||
|
||||
// Display a welcome message
|
||||
display.scroll("Hi! I'm ");
|
||||
display.scroll(deviceName);
|
||||
|
||||
// Display our name, visualised as a histogram in the display to aid identification.
|
||||
showNameHistogram(display);
|
||||
|
||||
while(1)
|
||||
{
|
||||
if (pairingStatus & MICROBIT_BLE_PAIR_REQUEST)
|
||||
{
|
||||
display.scroll("Pair: ");
|
||||
display.scroll(passKey);
|
||||
}
|
||||
|
||||
if (pairingStatus & MICROBIT_BLE_PAIR_COMPLETE)
|
||||
{
|
||||
if (pairingStatus & MICROBIT_BLE_PAIR_SUCCESSFUL)
|
||||
{
|
||||
MicroBitImage tick("0,0,0,0,0\n0,0,0,0,255\n0,0,0,255,0\n255,0,255,0,0\n0,255,0,0,0\n");
|
||||
display.print(tick,0,0,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
MicroBitImage cross("255,0,0,0,255\n0,255,0,255,0\n0,0,255,0,0\n0,255,0,255,0\n255,0,0,0,255\n");
|
||||
display.print(cross,0,0,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the device's ID code as a histogram on the LED matrix display.
|
||||
*/
|
||||
void MicroBitBLEManager::showNameHistogram(MicroBitDisplay &display)
|
||||
{
|
||||
uint32_t n = NRF_FICR->DEVICEID[1];
|
||||
int ld = 1;
|
||||
int d = MICROBIT_DFU_HISTOGRAM_HEIGHT;
|
||||
int h;
|
||||
|
||||
display.clear();
|
||||
for (int i=0; i<MICROBIT_DFU_HISTOGRAM_WIDTH;i++)
|
||||
{
|
||||
h = (n % d) / ld;
|
||||
|
||||
n -= h;
|
||||
d *= MICROBIT_DFU_HISTOGRAM_HEIGHT;
|
||||
ld *= MICROBIT_DFU_HISTOGRAM_HEIGHT;
|
||||
|
||||
for (int j=0; j<h+1; j++)
|
||||
display.image.setPixelValue(MICROBIT_DFU_HISTOGRAM_WIDTH-i-1, MICROBIT_DFU_HISTOGRAM_HEIGHT-j-1, 255);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,10 @@ MicroBitButtonService::MicroBitButtonService(BLEDevice &_ble) :
|
|||
// Initialise our characteristic values.
|
||||
buttonADataCharacteristicBuffer = 0;
|
||||
buttonBDataCharacteristicBuffer = 0;
|
||||
|
||||
// Set default security requirements
|
||||
buttonADataCharacteristic.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM);
|
||||
buttonBDataCharacteristic.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM);
|
||||
|
||||
GattCharacteristic *characteristics[] = {&buttonADataCharacteristic, &buttonBDataCharacteristic};
|
||||
GattService service(MicroBitButtonServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
|
||||
|
|
|
@ -38,6 +38,10 @@ MicroBitDFUService::MicroBitDFUService(BLEDevice &_ble) :
|
|||
controlByte = 0x00;
|
||||
flashCode = 0x00;
|
||||
|
||||
// Set default security requirements
|
||||
microBitDFUServiceControlCharacteristic.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM);
|
||||
microBitDFUServiceFlashCodeCharacteristic.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM);
|
||||
|
||||
GattCharacteristic *characteristics[] = {µBitDFUServiceControlCharacteristic, µBitDFUServiceFlashCodeCharacteristic};
|
||||
GattService service(MicroBitDFUServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
|
||||
|
||||
|
|
|
@ -34,6 +34,12 @@ MicroBitEventService::MicroBitEventService(BLEDevice &_ble) :
|
|||
|
||||
messageBusListenerOffset = 0;
|
||||
|
||||
// Set default security requirements
|
||||
microBitEventCharacteristic.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM);
|
||||
clientEventCharacteristic.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM);
|
||||
clientRequirementsCharacteristic.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM);
|
||||
microBitRequirementsCharacteristic->requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM);
|
||||
|
||||
GattCharacteristic *characteristics[] = {µBitEventCharacteristic, &clientEventCharacteristic, &clientRequirementsCharacteristic, microBitRequirementsCharacteristic};
|
||||
GattService service(MicroBitEventServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
|
||||
|
||||
|
|
|
@ -30,6 +30,11 @@ MicroBitIOPinService::MicroBitIOPinService(BLEDevice &_ble) :
|
|||
ioPinServiceADCharacteristicBuffer = 0;
|
||||
ioPinServiceIOCharacteristicBuffer = 0;
|
||||
memset(ioPinServiceIOData, 0, sizeof(ioPinServiceIOData));
|
||||
|
||||
// Set default security requirements
|
||||
ioPinServiceADCharacteristic.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM);
|
||||
ioPinServiceIOCharacteristic.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM);
|
||||
ioPinServiceDataCharacteristic->requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM);
|
||||
|
||||
GattCharacteristic *characteristics[] = {&ioPinServiceADCharacteristic, &ioPinServiceIOCharacteristic, ioPinServiceDataCharacteristic};
|
||||
GattService service(MicroBitIOPinServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
|
||||
|
|
|
@ -32,6 +32,11 @@ MicroBitLEDService::MicroBitLEDService(BLEDevice &_ble) :
|
|||
|
||||
matrixCharacteristic.setReadAuthorizationCallback(this, &MicroBitLEDService::onDataRead);
|
||||
|
||||
// Set default security requirements
|
||||
matrixCharacteristic.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM);
|
||||
textCharacteristic.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM);
|
||||
scrollingSpeedCharacteristic.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM);
|
||||
|
||||
GattCharacteristic *characteristics[] = {&matrixCharacteristic, &textCharacteristic, &scrollingSpeedCharacteristic};
|
||||
GattService service(MicroBitLEDServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
|
||||
|
||||
|
|
|
@ -33,7 +33,12 @@ MicroBitMagnetometerService::MicroBitMagnetometerService(BLEDevice &_ble) :
|
|||
magnetometerDataCharacteristicBuffer[2] = 0;
|
||||
magnetometerBearingCharacteristicBuffer = 0;
|
||||
magnetometerPeriodCharacteristicBuffer = uBit.compass.getPeriod();
|
||||
|
||||
|
||||
// Set default security requirements
|
||||
magnetometerDataCharacteristic.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM);
|
||||
magnetometerBearingCharacteristic.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM);
|
||||
magnetometerPeriodCharacteristic.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM);
|
||||
|
||||
GattCharacteristic *characteristics[] = {&magnetometerDataCharacteristic, &magnetometerBearingCharacteristic, &magnetometerPeriodCharacteristic};
|
||||
GattService service(MicroBitMagnetometerServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
|
||||
|
||||
|
|
|
@ -26,7 +26,11 @@ MicroBitTemperatureService::MicroBitTemperatureService(BLEDevice &_ble) :
|
|||
// Initialise our characteristic values.
|
||||
temperatureDataCharacteristicBuffer = 0;
|
||||
temperaturePeriodCharacteristicBuffer = uBit.thermometer.getPeriod();
|
||||
|
||||
|
||||
// Set default security requirements
|
||||
temperatureDataCharacteristic.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM);
|
||||
temperaturePeriodCharacteristic.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM);
|
||||
|
||||
GattCharacteristic *characteristics[] = {&temperatureDataCharacteristic, &temperaturePeriodCharacteristic};
|
||||
GattService service(MicroBitTemperatureServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
|
||||
|
||||
|
|
Loading…
Reference in New Issue