Skip to content

Commit 85fb846

Browse files
committed
Merge pull request arduino#90 from fallberg/rev_and_rng
Bugfixes and whitelisting support in signing backends
2 parents cb5e317 + 6fb7266 commit 85fb846

File tree

15 files changed

+479
-193
lines changed

15 files changed

+479
-193
lines changed

libraries/MySensors/MyConfig.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,31 @@ typedef MyHwATMega328 MyHwDriver;
1616
/**********************************
1717
* Message Signing Settings
1818
***********************************/
19+
// Disable to completly disable signing functionality in library
20+
#define MY_SIGNING_FEATURE
21+
1922
// Define a suitable timeout for a signature verification session
2023
// Consider the turnaround from a nonce being generated to a signed message being received
2124
// which might vary, especially in networks with many hops. 5s ought to be enough for anyone.
2225
#define MY_VERIFICATION_TIMEOUT_MS 5000
2326

27+
// Enable to turn on whitelisting
28+
// When enabled, a signing node will salt the signature with it's unique signature and nodeId.
29+
// The verifying node will look up the sender in a local table of trusted nodes and
30+
// do the corresponding salting in order to verify the signature.
31+
// For this reason, if whitelisting is enabled on one of the nodes in a sign-verify pair, both
32+
// nodes have to implement whitelisting for this to work.
33+
// Note that a node can still transmit a non-salted message (i.e. have whitelisting disabled)
34+
// to a node that has whitelisting enabled (assuming the receiver does not have a matching entry
35+
// for the sender in it's whitelist)
36+
//#define MY_SECURE_NODE_WHITELISTING
37+
2438
// MySigningAtsha204 default setting
2539
#define MY_ATSHA204_PIN 17 // A3 - pin where ATSHA204 is attached
2640

2741
// MySigningAtsha204Soft default settings
2842
#define MY_RANDOMSEED_PIN 7 // A7 - Pin used for random generation (do not connect anything to this)
43+
2944
// Key to use for HMAC calculation in MySigningAtsha204Soft (32 bytes)
3045
#define MY_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
3146
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00

libraries/MySensors/MySensor.cpp

Lines changed: 50 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@
1313

1414
#define DISTANCE_INVALID (0xFF)
1515

16+
#ifdef MY_SIGNING_FEATURE
1617
// Macros for manipulating signing requirement table
1718
#define DO_SIGN(node) (node == 0 ? (~doSign[0]&1) : (~doSign[node>>4]&(node%16)))
1819
#define SET_SIGN(node) (node == 0 ? (doSign[0]&=~1) : (doSign[node>>4]&=~(node%16)))
1920
#define CLEAR_SIGN(node) (node == 0 ? (doSign[0]|=1) : (doSign[node>>4]|=(node%16)))
21+
#endif
2022

2123
// Inline function and macros
2224
static inline MyMessage& build (MyMessage &msg, uint8_t sender, uint8_t destination, uint8_t sensor, uint8_t command, uint8_t type, bool enableAck) {
@@ -38,10 +40,16 @@ static inline bool isValidDistance( const uint8_t distance ) {
3840
}
3941

4042

41-
MySensor::MySensor(MyTransport &_radio, MySigning &_signer, MyHw &_hw)
43+
MySensor::MySensor(MyTransport &_radio, MyHw &_hw
44+
#ifdef MY_SIGNING_FEATURE
45+
, MySigning &_signer
46+
#endif
47+
)
4248
:
4349
radio(_radio),
50+
#ifdef MY_SIGNING_FEATURE
4451
signer(_signer),
52+
#endif
4553
hw(_hw)
4654
{
4755
}
@@ -63,8 +71,10 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b
6371
hw_readConfigBlock((void*)&nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig));
6472
// Read latest received controller configuration from EEPROM
6573
hw_readConfigBlock((void*)&cc, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(ControllerConfig));
74+
#ifdef MY_SIGNING_FEATURE
6675
// Read out the signing requirements from EEPROM
6776
hw_readConfigBlock((void*)doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, sizeof(doSign));
77+
#endif
6878

6979
if (isGateway) {
7080
nc.distance = 0;
@@ -128,13 +138,15 @@ void MySensor::setupNode() {
128138

129139
// Present node and request config
130140
if (!isGateway && nc.nodeId != AUTO) {
141+
#ifdef MY_SIGNING_FEATURE
131142
// Notify gateway (and possibly controller) about the signing preferences of this node
132143
sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(signer.requestSignatures()));
133144

134145
// If we do require signing, wait for the gateway to tell us how it prefer us to transmit our messages
135146
if (signer.requestSignatures()) {
136147
wait(2000);
137148
}
149+
#endif
138150

139151
// Send presentation for this radio node (attach
140152
present(NODE_SENSOR_ID, repeaterMode? S_ARDUINO_REPEATER_NODE : S_ARDUINO_NODE);
@@ -186,19 +198,47 @@ boolean MySensor::sendRoute(MyMessage &message) {
186198

187199
mSetVersion(message, PROTOCOL_VERSION);
188200

201+
#ifdef MY_SIGNING_FEATURE
189202
// If destination is known to require signed messages and we are the sender, sign this message unless it is an ACK or a handshake message
190203
if (DO_SIGN(message.destination) && message.sender == nc.nodeId && !mGetAck(message) && mGetLength(msg) &&
191204
(mGetCommand(message) != C_INTERNAL ||
192205
(message.type != I_GET_NONCE && message.type != I_GET_NONCE_RESPONSE && message.type != I_REQUEST_SIGNING &&
193206
message.type != I_ID_REQUEST && message.type != I_ID_RESPONSE &&
194207
message.type != I_FIND_PARENT && message.type != I_FIND_PARENT_RESPONSE))) {
195-
if (!sign(message)) {
208+
bool signOk = false;
209+
// Send nonce-request
210+
if (!sendRoute(build(tmpMsg, nc.nodeId, message.destination, message.sensor, C_INTERNAL, I_GET_NONCE, false).set(""))) {
211+
debug(PSTR("nonce tr err\n"));
212+
return false;
213+
}
214+
// We have to wait for the nonce to arrive before we can sign our original message
215+
// Other messages could come in-between. We trust process() takes care of them
216+
unsigned long enter = hw_millis();
217+
msgSign = message; // Copy the message to sign since message buffer might be touched in process()
218+
while (hw_millis() - enter < MY_VERIFICATION_TIMEOUT_MS) {
219+
if (process()) {
220+
if (mGetCommand(getLastMessage()) == C_INTERNAL && getLastMessage().type == I_GET_NONCE_RESPONSE) {
221+
// Proceed with signing if nonce has been received
222+
if (signer.putNonce(getLastMessage()) && signer.signMsg(msgSign)) {
223+
message = msgSign; // Write the signed message back
224+
signOk = true;
225+
}
226+
break;
227+
}
228+
}
229+
}
230+
if (hw_millis() - enter > MY_VERIFICATION_TIMEOUT_MS) {
231+
debug(PSTR("nonce tmo\n"));
232+
return false;
233+
}
234+
if (!signOk) {
196235
debug(PSTR("sign fail\n"));
197236
return false;
198237
}
199238
// After this point, only the 'last' member of the message structure is allowed to be altered if the message has been signed,
200239
// or signature will become invalid and the message rejected by the receiver
201240
} else mSetSigned(message, 0); // Message is not supposed to be signed, make sure it is marked unsigned
241+
#endif
202242

203243
if (dest == GATEWAY_ADDRESS || !repeaterMode) {
204244
// If destination is the gateway or if we aren't a repeater, let
@@ -313,10 +353,13 @@ boolean MySensor::process() {
313353
if (!radio.available(&to))
314354
return false;
315355

356+
#ifdef MY_SIGNING_FEATURE
316357
(void)signer.checkTimer(); // Manage signing timeout
317-
358+
#endif
359+
318360
uint8_t len = radio.receive((uint8_t *)&msg);
319361

362+
#ifdef MY_SIGNING_FEATURE
320363
// Before processing message, reject unsigned messages if signing is required and check signature (if it is signed and addressed to us)
321364
// Note that we do not care at all about any signature found if we do not require signing, nor do we care about ACKs (they are never signed)
322365
if (signer.requestSignatures() && msg.destination == nc.nodeId && mGetLength(msg) && !mGetAck(msg) &&
@@ -334,6 +377,7 @@ boolean MySensor::process() {
334377
return false; // This signed message has been tampered with!
335378
}
336379
}
380+
#endif
337381

338382
// Add string termination, good if we later would want to print it.
339383
msg.data[mGetLength(msg)] = '\0';
@@ -392,6 +436,7 @@ boolean MySensor::process() {
392436
}
393437
}
394438
return false;
439+
#ifdef MY_SIGNING_FEATURE
395440
} else if (type == I_GET_NONCE) {
396441
if (signer.getNonce(msg)) {
397442
sendRoute(build(msg, nc.nodeId, msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_GET_NONCE_RESPONSE, false));
@@ -406,7 +451,7 @@ boolean MySensor::process() {
406451
CLEAR_SIGN(msg.sender);
407452
}
408453
// Save updated table
409-
hw_writeConfigBlock((void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, (void*)doSign, sizeof(doSign));
454+
hw_writeConfigBlock((void*)doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, sizeof(doSign));
410455

411456
// Inform sender about our preference if we are a gateway, but only require signing if the sender required signing
412457
// We do not currently want a gateway to require signing from all nodes in a network just because it wants one node
@@ -420,6 +465,7 @@ boolean MySensor::process() {
420465
return false; // Signing request is an internal MySensor protocol message, no need to inform caller about this
421466
} else if (type == I_GET_NONCE_RESPONSE) {
422467
return true; // Just pass along nonce silently (no need to call callback for these)
468+
#endif
423469
} else if (sender == GATEWAY_ADDRESS) {
424470
bool isMetric;
425471

@@ -524,27 +570,3 @@ int8_t MySensor::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, ui
524570
return hw.sleep(interrupt1, mode1, interrupt2, mode2, ms) ;
525571
}
526572

527-
bool MySensor::sign(MyMessage &message) {
528-
if (!sendRoute(build(tmpMsg, nc.nodeId, message.destination, message.sensor, C_INTERNAL, I_GET_NONCE, false).set(""))) {
529-
return false;
530-
} else {
531-
// We have to wait for the nonce to arrive before we can sign our original message
532-
// Other messages could come in-between. We trust process() takes care of them
533-
unsigned long enter = hw_millis();
534-
msgSign = message; // Copy the message to sign since message buffer might be touched in process()
535-
while (hw_millis() - enter < 5000) {
536-
if (process()) {
537-
if (mGetCommand(getLastMessage()) == C_INTERNAL && getLastMessage().type == I_GET_NONCE_RESPONSE) {
538-
// Proceed with signing if nonce has been received
539-
if (signer.putNonce(getLastMessage()) && signer.signMsg(msgSign)) {
540-
message = msgSign; // Write the signed message back
541-
return true;
542-
}
543-
break;
544-
}
545-
}
546-
}
547-
}
548-
return false;
549-
}
550-

libraries/MySensors/MySensor.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818
#include "MyTransport.h"
1919
#include "MyTransportNRF24.h"
2020
#include "MyParser.h"
21+
#ifdef MY_SIGNING_FEATURE
2122
#include "MySigning.h"
2223
#include "MySigningNone.h"
24+
#endif
2325
#include "MyMessage.h"
2426
#include <stddef.h>
2527
#include <stdarg.h>
@@ -73,7 +75,11 @@ class MySensor
7375
* Creates a new instance of Sensor class.
7476
*
7577
*/
76-
MySensor(MyTransport &radio =*new MyTransportNRF24(), MySigning &signer=*new MySigningNone(), MyHw &hw=*new MyHwDriver());
78+
MySensor(MyTransport &radio =*new MyTransportNRF24(), MyHw &hw=*new MyHwDriver()
79+
#ifdef MY_SIGNING_FEATURE
80+
, MySigning &signer=*new MySigningNone()
81+
#endif
82+
);
7783

7884
/**
7985
* Begin operation of the MySensors library
@@ -233,14 +239,16 @@ class MySensor
233239
bool repeaterMode;
234240
bool autoFindParent;
235241
bool isGateway;
236-
uint16_t doSign[16]; // Bitfield indicating which sensors require signed communication
237242

238243
MyMessage msg; // Buffer for incoming messages.
239244
MyMessage tmpMsg ; // Buffer for temporary messages (acks and nonces among others).
245+
#ifdef MY_SIGNING_FEATURE
246+
uint16_t doSign[16]; // Bitfield indicating which sensors require signed communication
240247
MyMessage msgSign; // Buffer for message to sign.
248+
MySigning& signer;
249+
#endif
241250

242251
MyTransport& radio;
243-
MySigning& signer;
244252
MyHw& hw;
245253

246254
boolean sendWrite(uint8_t dest, MyMessage &message);
@@ -257,7 +265,6 @@ class MySensor
257265
void setupNode();
258266
void findParentNode();
259267
uint8_t crc8Message(MyMessage &message);
260-
bool sign(MyMessage &message);
261268
};
262269
#endif
263270

0 commit comments

Comments
 (0)