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
This commit is contained in:
@@ -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
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
Dummy signing backend. Does not provide any security measures.
|
||||
|
||||
Created by Patrick "Anticimex" Fallberg <patrick@fallberg.net>
|
||||
*/
|
||||
#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<sz; i++)
|
||||
{
|
||||
if (buf[i] < 0x10)
|
||||
{
|
||||
Serial.print('0'); // Because Serial.print does not 0-pad HEX
|
||||
}
|
||||
Serial.print(buf[i], HEX);
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
#else
|
||||
#define DEBUG_DUMMY_PRINTBUF(str, buf, sz)
|
||||
#endif
|
||||
|
||||
MySigningDriverDummy::MySigningDriverDummy() : MySigningDriver() {
|
||||
verification_ongoing = false;
|
||||
current_nonce = 0;
|
||||
}
|
||||
|
||||
bool MySigningDriverDummy::getNonce(MyMessage &msg) {
|
||||
uint8_t nonce_buf[2];
|
||||
nonce_buf[0] = SIGNING_IDENTIFIER;
|
||||
// This is normally a buffer but for our minimal driver we use a single byte
|
||||
// We at least use a new nonce for every session
|
||||
nonce_buf[1] = ++current_nonce;
|
||||
msg.set(nonce_buf, 2);
|
||||
verification_ongoing = true;
|
||||
timestamp = millis(); // Set timestamp to determine when to purge nonce
|
||||
// Be a little fancy to handle turnover (prolong the time allowed to timeout after turnover)
|
||||
// Note that if message is "too" quick, and arrives before turnover, it will be rejected
|
||||
// but this is consider such a rare case that it is accepted and rejects are 'safe'
|
||||
if (timestamp + VERIFICATION_TIMEOUT_MS < millis()) timestamp = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MySigningDriverDummy::checkTimer() {
|
||||
if (verification_ongoing) {
|
||||
if (millis() < timestamp || millis() > 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
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
Dummy signing backend. Does not provide any security measures.
|
||||
|
||||
Created by Patrick "Anticimex" Fallberg <patrick@fallberg.net>
|
||||
*/
|
||||
#ifndef MySigningDriverDummy_h
|
||||
#define MySigningDriverDummy_h
|
||||
|
||||
#include "MyConfig.h"
|
||||
#include "MySigningDriver.h"
|
||||
#include <stdint.h>
|
||||
|
||||
// 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
|
||||
Reference in New Issue
Block a user