MAXREFDES143#: DeepCover Embedded Security in IoT Authenticated Sensing & Notification
Dependencies: MaximInterface mbed
The MAXREFDES143# is an Internet of Things (IoT) embedded security reference design, built to protect an industrial sensing node by means of authentication and notification to a web server. The hardware includes a peripheral module representing a protected sensor node monitoring operating temperature and remaining life of a filter (simulated through ambient light sensing) and an mbed shield representing a controller node responsible for monitoring one or more sensor nodes. The design is hierarchical with each controller node communicating data from connected sensor nodes to a web server that maintains a centralized log and dispatches notifications as necessary. The mbed shield contains a Wi-Fi module, a DS2465 coprocessor with 1-Wire® master function, an LCD, LEDs, and pushbuttons. The protected sensor node contains a DS28E15 authenticator, a DS7505 temperature sensor, and a MAX44009 light sensor. The mbed shield communicates to a web server by the onboard Wi-Fi module and to the protected sensor node with I2C and 1-Wire. The MAXREFDES143# is equipped with a standard shield connector for immediate testing using an mbed board such as the MAX32600MBED#. The simplicity of this design enables rapid integration into any star-topology IoT network requiring the heightened security with low overhead provided by the SHA-256 symmetric-key algorithm.
More information about the MAXREFDES143# is available on the Maxim Integrated website.
Diff: main.cpp
- Revision:
- 32:0a09505a656d
- Parent:
- 29:590a7561318b
diff -r 7b10bcb3e0fc -r 0a09505a656d main.cpp
--- a/main.cpp Tue Apr 04 14:10:48 2017 -0500
+++ b/main.cpp Mon Nov 06 17:34:13 2017 -0600
@@ -28,278 +28,255 @@
* trademarks, maskwork rights, or any other form of intellectual
* property whatsoever. Maxim Integrated Products, Inc. retains all
* ownership rights.
-*******************************************************************************
-*/
+*******************************************************************************/
#include <sstream>
-
+#include <mbed.h>
+#include <MaximInterface/Devices/DS2465.hpp>
+#include <MaximInterface/Platforms/mbed/I2CMaster.hpp>
+#include <MaximInterface/Platforms/mbed/Sleep.hpp>
+#include <MaximInterface/Utilities/RomId.hpp>
#include "SensorData.hpp"
#include "WebServerInterface.hpp"
#include "Factory.hpp"
#include "SensorNode.hpp"
-#include "Masters/DS2465/DS2465.h"
#include "Display.hpp"
-#include "RomId/RomId.h"
#include "ESP8266.hpp"
-#include "mbed.h"
-using OneWire::RomId;
-using OneWire::DS2465;
+using namespace MaximInterface;
/// Main status for the program.
-enum Status
-{
- InitializingController, ///< Configure DS2465 and connect to network.
- DisplaySessionId, ///< Display ID for use with website.
+enum Status {
+ InitializingController, ///< Configure DS2465 and connect to network.
+ DisplaySessionId, ///< Display ID for use with website.
SensorNodeNeedsDetection, ///< Prompt user to insert Sensor Node.
- DetectingSensorNode, ///< Check if Sensor Node present.
+ DetectingSensorNode, ///< Check if Sensor Node present.
SensorNodeNeedsProvision, ///< Sensor Node needs to be provisioned.
- ProvisioningSensorNode, ///< Provisioning Sensor Node to factory defaults.
- NormalOperation, ///< The normal demo operation state.
- SensorNodeNotAuthentic, ///< Sensor Node failed authentication check.
+ ProvisioningSensorNode, ///< Provisioning Sensor Node to factory defaults.
+ NormalOperation, ///< The normal demo operation state.
+ SensorNodeNotAuthentic, ///< Sensor Node failed authentication check.
ControllerInitializationError, ///< Failed to initialize Controller.
- ControllerHardwareError, ///< Controller hardware failed unexpectedly.
- SensorNodeHardwareError ///< Sensor Node hardware failed unexpectedly.
+ ControllerHardwareError, ///< Controller hardware failed unexpectedly.
+ SensorNodeHardwareError ///< Sensor Node hardware failed unexpectedly.
};
/// @{
/// Configuration options.
-static const unsigned int webPostIntervalMs = 10000;
-static const unsigned int webPostRetryIntervalMs = 1000;
-static const uint8_t maxConsecutiveWebPostErrors = 3;
+static const int webPostIntervalMs = 10000;
+static const int webPostRetryIntervalMs = 1000;
+static const int maxConsecutiveWebPostErrors = 3;
/// @}
/// @{
/// LCD display colors.
-static const Display::Color Teal = { 0x00, 0xB2, 0xA9 };
-static const Display::Color Red = { 0xFF, 0x00, 0x00 };
-static const Display::Color Green = { 0x00, 0xFF, 0x00 };
-static const Display::Color Purple = { 0x6E, 0x25, 0x85 };
+static const Display::Color Teal = {0x00, 0xB2, 0xA9};
+static const Display::Color Red = {0xFF, 0x00, 0x00};
+static const Display::Color Green = {0x00, 0xFF, 0x00};
+static const Display::Color Purple = {0x6E, 0x25, 0x85};
/// @}
/// @{
/// Peripheral and pin definitions
-static Serial pc(USBTX, USBRX);
static DigitalIn provisionButton(D13);
static DigitalIn invalidateButton(D5);
static DigitalOut tempAlarmLed(D11, 1);
static DigitalOut filterLifeAlarmLed(D10, 1);
static I2C i2c(D14, D15);
static Display lcd(i2c, 0x78, 0x98);
-static DS2465 ds2465(i2c, 0x30);
+static MaximInterface::mbed::I2CMaster i2cWrapper(i2c);
+static DS2465 ds2465(MaximInterface::mbed::Sleep::instance(), i2cWrapper, 0x30);
static SensorNode sensorNode(i2c, 0x90, 0x94, ds2465);
static ESP8266 esp8266(D1, D0, D2, D3, 38400);
static WebServerInterface webIntf(esp8266);
/// @}
-static bool useInvalidSecret = false; ///< Imitate an invalid controller when posting to web server.
+/// Imitate an invalid controller when posting to web server.
+static bool useInvalidSecret = false;
static unsigned int randomSeed = 0; ///< Create extra entropy for challenge.
static Status currentStatus = InitializingController;
static bool result = false;
-static uint8_t consecutiveWebPostErrors = 0; ///< Account for a few network errors in case of flaky connection.
+/// Account for a few network errors in case of flaky connection.
+static uint8_t consecutiveWebPostErrors = 0;
static Timer webPostTimer; ///< Software timer to track web posting interval.
-static Timer retryTimer; ///< Software timer to track authentication retries.
+static Timer retryTimer; ///< Software timer to track authentication retries.
-static void blinkLeds(unsigned int time_ms); ///< Invert LEDs for a given amount of time.
-static bool buttonPressed(DigitalIn & button); ///< Checks if button is pressed (returns true) and waits for release.
-static void displayStatus(Status status); ///< Display status message on LCD.
-static void displaySensorData(const SensorData & sensorData); ///< Display sensor data on the LCD.
-static bool readWebSessionId(OneWire::RomId & sessionId); ///< Read device's web session ID from it's nonvolatile storage.
+/// Invert LEDs for a given amount of time.
+static void blinkLeds(int time_ms);
+/// Checks if button is pressed (returns true) and waits for release.
+static bool buttonPressed(DigitalIn & button);
+/// Display status message on LCD.
+static void displayStatus(Status status);
+/// Display sensor data on the LCD.
+static void displaySensorData(const SensorData & sensorData);
+/// Read device's web session ID from it's nonvolatile storage.
+static bool readWebSessionId(RomId & sessionId);
#ifdef ASSEMBLY_TEST
-#include "AssemblyTest.cpp"
+#include "AssemblyTest.hpp"
#endif
-int main()
-{
+int main() {
blinkLeds(500);
-
+
#ifdef ASSEMBLY_TEST
assemblyTest();
#endif
-
- while (true)
- {
+
+ while (true) {
Status nextStatus = currentStatus;
- switch (currentStatus)
- {
+ switch (currentStatus) {
case InitializingController:
- pc.baud(115200);
i2c.frequency(100000);
webPostTimer.start();
-
+
// Set initial LCD state
lcd.initialize();
displayStatus(currentStatus);
-
+
// Connect to Wifi network
result = webIntf.initialize();
-
+
// Read session ID
- if (result)
- {
- OneWire::RomId sessionId;
+ if (result) {
+ RomId sessionId;
result = readWebSessionId(sessionId);
- if (result)
- {
- webIntf.setSessionId(sessionId);
+ if (result) {
+ webIntf.setSessionId(sessionId);
}
}
-
+
// Provision DS2465 with master secret and page data
- if (result)
- {
+ if (result) {
result = provisionCoprocessor(ds2465);
}
-
- if (result)
- {
+
+ if (result) {
nextStatus = DisplaySessionId;
- }
- else
- {
+ } else {
nextStatus = ControllerInitializationError;
}
break;
-
+
case DisplaySessionId:
// Wait for user to press Provision button
- if (buttonPressed(provisionButton))
- {
+ if (buttonPressed(provisionButton)) {
nextStatus = SensorNodeNeedsDetection;
}
break;
-
+
case SensorNodeNeedsDetection:
// Wait for user to press Provision button
- if (buttonPressed(provisionButton))
- {
+ if (buttonPressed(provisionButton)) {
nextStatus = DetectingSensorNode;
}
break;
-
+
case DetectingSensorNode:
// Perform Sensor Node detection sequence
- switch (sensorNode.detect(randomSeed))
- {
+ switch (sensorNode.detect(randomSeed)) {
case SensorNode::UnableToCommunicate:
default:
nextStatus = SensorNodeHardwareError;
break;
-
+
case SensorNode::NotProvisioned:
nextStatus = SensorNodeNeedsProvision;
break;
-
+
case SensorNode::NotAuthentic:
nextStatus = SensorNodeNotAuthentic;
break;
-
+
case SensorNode::Authentic:
nextStatus = NormalOperation;
break;
}
break;
-
+
case SensorNodeNeedsProvision:
// Wait for user to press Provision button
- if (buttonPressed(provisionButton))
- {
+ if (buttonPressed(provisionButton)) {
nextStatus = ProvisioningSensorNode;
}
break;
-
- case ProvisioningSensorNode:
- if (!buttonPressed(invalidateButton)) // Provision normally
- {
- if (provisionSensorNode(sensorNode, true))
- {
+
+ case ProvisioningSensorNode:
+ if (!buttonPressed(invalidateButton)) { // Provision normally
+ if (provisionSensorNode(sensorNode, true)) {
nextStatus = NormalOperation;
- }
- else
- {
+ } else {
nextStatus = SensorNodeNotAuthentic;
}
- }
- else // Invalidate button also pressed; Load invalid secret
- {
+ } else { // Invalidate button also pressed; Load invalid secret
// Provision with invalid secret
- if (provisionSensorNode(sensorNode, false))
- {
+ if (provisionSensorNode(sensorNode, false)) {
nextStatus = NormalOperation;
- }
- else
- {
+ } else {
nextStatus = SensorNodeHardwareError;
}
}
break;
-
- case NormalOperation:
+
+ case NormalOperation:
// Check if user pressed Provision button
- if (buttonPressed(provisionButton))
- {
+ if (buttonPressed(provisionButton)) {
// Re-provision Sensor Node
nextStatus = ProvisioningSensorNode;
}
// Check if user pressed Invalidate button
- else if (buttonPressed(invalidateButton))
- {
+ else if (buttonPressed(invalidateButton)) {
// Toggle between using valid and invalid secret
// 1 blink = invalid; 2 blinks = valid
useInvalidSecret = !useInvalidSecret;
blinkLeds(100);
- if (!useInvalidSecret)
- {
+ if (!useInvalidSecret) {
wait_ms(100);
blinkLeds(100);
}
}
// Check node and display measurements
- else
- {
+ else {
SensorData sensorData;
// Read sensor data with authentication
- switch (sensorNode.authenticatedReadSensorData(randomSeed, sensorData))
- {
+ switch (
+ sensorNode.authenticatedReadSensorData(randomSeed, sensorData)) {
case SensorNode::Authentic:
// Update measurements on LCD
displaySensorData(sensorData);
-
+
// Update alarm LEDs
- tempAlarmLed = !sensorData.tempAlarm(); // Active Low
+ tempAlarmLed = !sensorData.tempAlarm(); // Active Low
filterLifeAlarmLed = !sensorData.filterLifeAlarm(); // Active Low
-
+
// Send measurements to web if time interval reached
- if (static_cast<unsigned int>(webPostTimer.read_ms()) >= webPostIntervalMs)
- {
+ if (webPostTimer.read_ms() >= webPostIntervalMs) {
// Format, sign, and transmit data to web server
- result = webIntf.authPostHttpEvent(ds2465, SensorDataEvent, WebServerInterface::formatSensorDataPostBody(sensorData), !useInvalidSecret);
- if (result)
- {
+ result = webIntf.authPostHttpEvent(
+ ds2465, SensorDataEvent,
+ WebServerInterface::formatSensorDataPostBody(sensorData),
+ !useInvalidSecret);
+ if (result) {
// Reset timer count after logging sample complete
webPostTimer.reset();
consecutiveWebPostErrors = 0;
}
// There was likely an error establishing a web connection
- else if (++consecutiveWebPostErrors < maxConsecutiveWebPostErrors)
- {
+ else if (++consecutiveWebPostErrors < maxConsecutiveWebPostErrors) {
// Wait and try again
wait_ms(webPostRetryIntervalMs);
}
// Too many retry attempts
- else
- {
+ else {
// Assume we have lost network connection
nextStatus = ControllerHardwareError;
}
}
break;
-
+
case SensorNode::NotAuthentic:
nextStatus = SensorNodeNotAuthentic;
break;
-
+
case SensorNode::UnableToCommunicate:
default:
nextStatus = SensorNodeHardwareError;
@@ -307,51 +284,45 @@
}
}
break;
-
+
case SensorNodeNotAuthentic:
// Wait for some time before retrying authentication
retryTimer.reset();
retryTimer.start();
- do
- {
+ do {
// Wait for user to press Provision button
- if (buttonPressed(provisionButton))
- {
+ if (buttonPressed(provisionButton)) {
nextStatus = ProvisioningSensorNode;
break;
}
// Try to authenticate and return to normal operation
- else if (static_cast<unsigned int>(webPostTimer.read_ms()) >= webPostIntervalMs)
- {
+ else if (webPostTimer.read_ms() >= webPostIntervalMs) {
// Send event message to server
- result = webIntf.authPostHttpEvent(ds2465, InvalidSensorEvent, "", !useInvalidSecret);
- if (result)
- {
+ result = webIntf.authPostHttpEvent(ds2465, InvalidSensorEvent, "",
+ !useInvalidSecret);
+ if (result) {
// Reset timer count after logging complete
webPostTimer.reset();
consecutiveWebPostErrors = 0;
-
+
// Try to authenticate again
nextStatus = SensorNodeNeedsDetection;
- }
- else if (++consecutiveWebPostErrors < maxConsecutiveWebPostErrors)
- {
+ } else if (++consecutiveWebPostErrors < maxConsecutiveWebPostErrors) {
// There was likely an error establishing a web connection
// Wait and try again
wait_ms(webPostRetryIntervalMs);
}
// Too many retry attempts
- else
- {
+ else {
// Assume we have lost network connection
nextStatus = ControllerHardwareError;
break;
}
}
- } while (static_cast<unsigned int>(retryTimer.read_ms()) < webPostIntervalMs);
+ } while (retryTimer.read_ms() < webPostIntervalMs);
retryTimer.stop();
break;
-
+
case ControllerInitializationError:
case ControllerHardwareError:
case SensorNodeHardwareError:
@@ -360,12 +331,11 @@
break;
}
// Check if status changed
- if (currentStatus != nextStatus)
- {
+ if (currentStatus != nextStatus) {
currentStatus = nextStatus;
displayStatus(currentStatus); // Display status message on LCD
}
-
+
// Change seed value on every loop pass
randomSeed++;
}
@@ -373,8 +343,7 @@
/// Blink all LEDs for a certain amount of time.
/// @param time_ms Time in ms to blink for.
-static void blinkLeds(unsigned int time_ms)
-{
+static void blinkLeds(int time_ms) {
tempAlarmLed = !tempAlarmLed;
filterLifeAlarmLed = !filterLifeAlarmLed;
wait_ms(time_ms);
@@ -385,12 +354,11 @@
/// Check if a button is pressed and wait for it to be release.
/// @param button Active low button to check.
/// @returns True if pressed.
-static bool buttonPressed(DigitalIn & button)
-{
+static bool buttonPressed(DigitalIn & button) {
const int buttonPressed = 0; // Active low
- if (button == buttonPressed)
- {
- while (button == buttonPressed) ;
+ if (button == buttonPressed) {
+ while (button == buttonPressed)
+ ;
return true;
}
// else
@@ -398,60 +366,58 @@
}
/// Display the current status of the Controller on the LCD display.
-static void displayStatus(Status status)
-{
- switch (status)
- {
+static void displayStatus(Status status) {
+ switch (status) {
case InitializingController:
lcd.writeMessage("Initializing Controller...");
lcd.setBackLightColor(Teal);
break;
-
+
case DisplaySessionId:
lcd.writeLine("ID: " + webIntf.sessionIdString(), Display::FirstLine);
lcd.writeLine("Provision to begin", Display::SecondLine);
lcd.setBackLightColor(Teal);
break;
-
+
case SensorNodeNeedsDetection:
lcd.writeMessage("Insert Sensor Node and press Provision");
lcd.setBackLightColor(Teal);
break;
-
+
case DetectingSensorNode:
lcd.writeMessage("Detecting Sensor Node...");
lcd.setBackLightColor(Teal);
break;
-
+
case SensorNodeNeedsProvision:
lcd.writeMessage("Sensor Node Needs Provision");
lcd.setBackLightColor(Teal);
break;
-
+
case ProvisioningSensorNode:
lcd.writeMessage("Provisioning Sensor Node");
lcd.setBackLightColor(Teal);
break;
-
+
case NormalOperation:
// Everything handled in displaySensorData()
break;
-
+
case SensorNodeNotAuthentic:
lcd.writeMessage("Sensor Node Not Authentic");
lcd.setBackLightColor(Purple);
break;
-
+
case ControllerInitializationError:
lcd.writeMessage("Initialization Error Check Wi-Fi");
lcd.setBackLightColor(Red);
break;
-
+
case ControllerHardwareError:
lcd.writeMessage("Controller Hardware Error: Check Wi-Fi");
lcd.setBackLightColor(Red);
break;
-
+
case SensorNodeHardwareError:
lcd.writeMessage("Sensor Node Hardware Error");
lcd.setBackLightColor(Red);
@@ -460,13 +426,13 @@
}
/// Display sensor data on the LCD display during normal operation.
-static void displaySensorData(const SensorData & sensorData)
-{
+static void displaySensorData(const SensorData & sensorData) {
std::ostringstream stream;
stream << "Chiller Temp: " << static_cast<int>(sensorData.temp) << "C";
lcd.writeCompleteLine(stream.str(), Display::FirstLine);
stream.str(""); // Clear stream
- stream << "Filter Life: " << static_cast<unsigned int>(sensorData.filterLife) << "%";
+ stream << "Filter Life: " << static_cast<unsigned int>(sensorData.filterLife)
+ << "%";
lcd.writeCompleteLine(stream.str(), Display::SecondLine);
lcd.setBackLightColor(Green);
}
@@ -475,20 +441,20 @@
/// @note Session ID is taken from the ROM ID of the MAX66242.
/// @param[out] Session ID string.
/// @returns True on success.
-static bool readWebSessionId(OneWire::RomId & sessionId)
-{
+static bool readWebSessionId(RomId & sessionId) {
const uint8_t I2C_address = 0x32;
const uint8_t ROM_address = 0x68;
RomId romId;
-
+
// Set register pointer
if (i2c.write(I2C_address, reinterpret_cast<const char *>(&ROM_address), 1) != 0)
return false;
// Read ROM ID
- if (i2c.read(I2C_address, reinterpret_cast<char *>(romId.buffer.data()), romId.buffer.size()) != 0)
+ if (i2c.read(I2C_address, reinterpret_cast<char *>(romId.data()),
+ romId.size()) != 0)
return false;
// Check if CRC valid
- if (!romId.valid())
+ if (!valid(romId))
return false;
sessionId = romId;
return true;
MAXREFDES143#: DeepCover Embedded Security in IoT Authenticated Sensing & Notification