From fca0d4b5449c6ae6ab73f1e555be7deab99a650e Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sat, 7 Feb 2015 09:52:37 +0100 Subject: [PATCH] Dummy signing driver backend The dummy signing driver implements the most rudimentary form of signing. No pre-shared key is used, nonce is simply incremeted each turn and signature is only calculated on the fist byte using data XOR nonce. This driver is intended for library debugging and sensor network integrity verification (signed messages will force the radio to transmit all 32 bytes of data). It does check SIGNING_IDENTIFIER byte to avoid illegal mixing of signing backends in the network (as seen by this node) and it does verify proper execution order on the API. The dummy driver rejects all other signing backend protocols. Signing backend is selected in MyConfig.h --- libraries/MySensors/MyConfig.h | 14 +- libraries/MySensors/MySigningDriverDummy.cpp | 143 +++++++++++++++++++ libraries/MySensors/MySigningDriverDummy.h | 36 +++++ 3 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 libraries/MySensors/MySigningDriverDummy.cpp create mode 100644 libraries/MySensors/MySigningDriverDummy.h diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 96f2253..ce4f0aa 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -15,9 +15,13 @@ #define MYSENSORS_RF_NRF24 //#define MYSENSORS_RF_RF69 +// Choose signing backend by enabling one of the following +#define MYSENSORS_SIGNING_DUMMY - - +// Define a suitable timeout for a signature verification session +// Consider the turnaround from a nonce being generated to a signed message being received +// which might vary, especially in networks with many hops. 5s ought to be enough for anyone. +#define VERIFICATION_TIMEOUT_MS 5000 #ifdef MYSENSORS_RF_NRF24 #include "MyRFDriverNRF24.h" @@ -29,6 +33,12 @@ typedef class MyRFDriverNRF24 MyRFDriverClass; typedef class MyRFDriverRF69 MyRFDriverClass; #endif +#ifdef MYSENSORS_SIGNING_DUMMY +#include "MySigningDriverDummy.h" +#define SIGNING_IDENTIFIER (0) // Reserved for dummy implementation, will not work with other backends +typedef class MySigningDriverDummy MySigningDriverClass; +#endif + /*** * Enable/Disable debug logging */ diff --git a/libraries/MySensors/MySigningDriverDummy.cpp b/libraries/MySensors/MySigningDriverDummy.cpp new file mode 100644 index 0000000..51d418f --- /dev/null +++ b/libraries/MySensors/MySigningDriverDummy.cpp @@ -0,0 +1,143 @@ +/* + Dummy signing backend. Does not provide any security measures. + + Created by Patrick "Anticimex" Fallberg +*/ +#include "MySigningDriver.h" +#include "MySigningDriverDummy.h" + +#ifdef MYSENSORS_SIGNING_DUMMY +// Uncomment this to get some useful serial debug info (Serial.print and Serial.println expected) +//#define DEBUG_DUMMY_SIGNING + +#ifdef DEBUG_DUMMY_SIGNING +#define DEBUG_DUMMY_PRINTLN(args) Serial.println(args) +#else +#define DEBUG_DUMMY_PRINTLN(args) +#endif + +#ifdef DEBUG_DUMMY_SIGNING +static void DEBUG_DUMMY_PRINTBUF(char* str, uint8_t* buf, uint8_t sz) +{ + int i; + Serial.println(str); + for (int i=0; i timestamp + VERIFICATION_TIMEOUT_MS) { + DEBUG_DUMMY_PRINTLN("Verification timeout"); + // Purge nonce + current_nonce = 0; // purge nonce when used + verification_ongoing = false; + return false; + } + } + return true; +} + +bool MySigningDriverDummy::putNonce(MyMessage &msg) { + if (mGetLength(msg) != 2) { + DEBUG_DUMMY_PRINTLN("Incoming nonce with incorrect size"); + return false; // We require a signing identifier and a 1byte nonce + } + + if (((uint8_t*)msg.getCustom())[0] != SIGNING_IDENTIFIER) { + DEBUG_DUMMY_PRINTLN("Incorrect signing identifier"); + return false; + } + + current_nonce = ((uint8_t*)msg.getCustom())[1]; + return true; +} + +bool MySigningDriverDummy::signMsg(MyMessage &msg) { + // If we cannot fit any signature in the message, refuse to sign it + if (mGetLength(msg) > MAX_PAYLOAD-2) { + DEBUG_DUMMY_PRINTLN("Cannot fit any signature to this message"); + return false; + } + + // Calculate signature of message + mSetSigned(msg, 1); // make sure signing flag is set before signature is calculated + DEBUG_DUMMY_PRINTBUF("Message to sign:", (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); + uint8_t signature = msg.data[0] ^ current_nonce; + msg.data[mGetLength(msg)] = SIGNING_IDENTIFIER; // Add signing identifier + msg.data[mGetLength(msg)+1] = signature; + current_nonce = 0; // purge nonce when used + return true; +} + +bool MySigningDriverDummy::verifyMsg(MyMessage &msg) { + if (!verification_ongoing) { + DEBUG_DUMMY_PRINTLN("No active verification session"); + return false; + } else { + // Make sure we have not expired + if (!checkTimer()) { + return false; + } + + verification_ongoing = false; + + if (msg.data[mGetLength(msg)] != SIGNING_IDENTIFIER) { + DEBUG_DUMMY_PRINTLN("Incorrect signing identifier"); + return false; + } + + DEBUG_DUMMY_PRINTBUF("Message to verify:", (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); + DEBUG_DUMMY_PRINTBUF("Signature in message:", (uint8_t*)&msg.data[mGetLength(msg)], 2); + + // The dummy signing is the nonce XOR the first payload byte, + // so we "verify" by redoing that calculation with the nonce we transmitted + // Message without a payload this implementation always accepts as signed and messages that cannot + // fit a signature are also accepted as signed + if (mGetLength(msg) && mGetLength(msg) < MAX_PAYLOAD-2) { + uint8_t signature = msg.data[0] ^ current_nonce; + if (msg.data[mGetLength(msg)+1] != signature) { + DEBUG_DUMMY_PRINTBUF("Signature bad. Calculated signature:", &signature, 1); + return false; + } else { + DEBUG_DUMMY_PRINTLN("Signature ok"); + return true; + } + } else { + DEBUG_DUMMY_PRINTLN("No signature in message"); + return false; + } + } +} +#endif diff --git a/libraries/MySensors/MySigningDriverDummy.h b/libraries/MySensors/MySigningDriverDummy.h new file mode 100644 index 0000000..74b88a6 --- /dev/null +++ b/libraries/MySensors/MySigningDriverDummy.h @@ -0,0 +1,36 @@ +/* + Dummy signing backend. Does not provide any security measures. + + Created by Patrick "Anticimex" Fallberg +*/ +#ifndef MySigningDriverDummy_h +#define MySigningDriverDummy_h + +#include "MyConfig.h" +#include "MySigningDriver.h" +#include + +// The dummy signing driver implements the most rudimentary form of signing +// No pre-shared key is used, nonce is simply incremeted each turn and signature +// is only calculated on the fist byte using data XOR nonce. +// This driver is intended for library debugging and sensor network integrity +// verification (signed messages will force the radio to transmit all 32 bytes of data). +// It does check SIGNING_IDENTIFIER byte to avoid illegal mixing of signing back-ends in +// the network (as seen by this node) and it does verify proper execution order on the API. +// The dummy driver rejects all other back-ends. +class MySigningDriverDummy : public MySigningDriver +{ +public: + MySigningDriverDummy(); + bool getNonce(MyMessage &msg); + bool checkTimer(void); + bool putNonce(MyMessage &msg); + bool signMsg(MyMessage &msg); + bool verifyMsg(MyMessage &msg); +private: + unsigned long timestamp; + bool verification_ongoing; + uint8_t current_nonce; +}; + +#endif