Skip to content

Commit 79be69b

Browse files
committed
Support for gateways to request signed messages
Various fixes and tweaks to permit a gateway to request signatures from nodes. The following messages will not be signed (nor verified): * All signing-related handshake messages * All ID-related handshake messages * All ACKs An important change is that the polarity for the signing request flags stored in EEPROM has changed. '0' now means signing required. This ensures that if the "ClearEepromConfig" sketch is executed, signing requests will be turned off by default. As a consequence, it is recommended to clear EEPROM if signing will be used to ensure all nodes default to a non-signing state.
1 parent 89076d5 commit 79be69b

File tree

1 file changed

+31
-15
lines changed

1 file changed

+31
-15
lines changed

libraries/MySensors/MySensor.cpp

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
#define DISTANCE_INVALID (0xFF)
1515

1616
// Macros for manipulating signing requirement table
17-
#define DO_SIGN(node) (doSign[node>>4]&(node%16))
18-
#define SET_SIGN(node) (doSign[node>>4]|=(node%16))
19-
#define CLEAR_SIGN(node) (doSign[node>>4]&=~(node%16))
17+
#define DO_SIGN(node) (node == 0 ? (~doSign[0]&1) : (~doSign[node>>4]&(node%16)))
18+
#define SET_SIGN(node) (node == 0 ? (doSign[0]&=~1) : (doSign[node>>4]&=~(node%16)))
19+
#define CLEAR_SIGN(node) (node == 0 ? (doSign[0]|=1) : (doSign[node>>4]|=(node%16)))
2020

2121
// Inline function and macros
2222
static inline MyMessage& build (MyMessage &msg, uint8_t sender, uint8_t destination, uint8_t sensor, uint8_t command, uint8_t type, bool enableAck) {
@@ -132,12 +132,17 @@ void MySensor::setupNode() {
132132

133133
// Present node and request config
134134
if (!isGateway && nc.nodeId != AUTO) {
135-
// Send presentation for this radio node (attach
136-
present(NODE_SENSOR_ID, repeaterMode? S_ARDUINO_REPEATER_NODE : S_ARDUINO_NODE);
137-
138135
// Notify gateway (and possibly controller) about the signing preferences of this node
139136
sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(signer.requestSignatures()));
140137

138+
// If we do require signing, wait for the gateway to tell us how it perfer us to transmit our messages
139+
if (signer.requestSignatures()) {
140+
wait(2000);
141+
}
142+
143+
// Send presentation for this radio node (attach
144+
present(NODE_SENSOR_ID, repeaterMode? S_ARDUINO_REPEATER_NODE : S_ARDUINO_NODE);
145+
141146
// Send a configuration exchange request to controller
142147
// Node sends parent node. Controller answers with latest node configuration
143148
// which is picked up in process()
@@ -185,9 +190,12 @@ boolean MySensor::sendRoute(MyMessage &message) {
185190

186191
mSetVersion(message, PROTOCOL_VERSION);
187192

188-
// If destination is known to require signed messages and we are the sender, sign this message unless it is an ACK or a signing handshake message
193+
// 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
189194
if (DO_SIGN(message.destination) && message.sender == nc.nodeId && !mGetAck(message) && mGetLength(msg) &&
190-
(mGetCommand(message) != C_INTERNAL || (message.type != I_GET_NONCE && message.type != I_GET_NONCE_RESPONSE && message.type != I_REQUEST_SIGNING))) {
195+
(mGetCommand(message) != C_INTERNAL ||
196+
(message.type != I_GET_NONCE && message.type != I_GET_NONCE_RESPONSE && message.type != I_REQUEST_SIGNING &&
197+
message.type != I_ID_REQUEST && message.type != I_ID_RESPONSE &&
198+
message.type != I_FIND_PARENT && message.type != I_FIND_PARENT_RESPONSE))) {
191199
if (!sign(message)) {
192200
debug(PSTR("Message signing failed\n"));
193201
return false;
@@ -313,10 +321,16 @@ boolean MySensor::process() {
313321
uint8_t len = radio.receive((uint8_t *)&msg);
314322

315323
// Before processing message, reject unsigned messages if signing is required and check signature (if it is signed and addressed to us)
316-
// Note that we do not care at all about any signature found if we do not require signing
317-
if (signer.requestSignatures() && msg.destination == nc.nodeId && mGetLength(msg) &&
318-
(mGetCommand(msg) != C_INTERNAL || (msg.type != I_GET_NONCE_RESPONSE && msg.type != I_GET_NONCE && msg.type != I_REQUEST_SIGNING))) {
319-
if (!mGetSigned(msg)) return false; // Received an unsigned message but we do require signing. This message gets nowhere!
324+
// 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)
325+
if (signer.requestSignatures() && msg.destination == nc.nodeId && mGetLength(msg) && !mGetAck(msg) &&
326+
(mGetCommand(msg) != C_INTERNAL ||
327+
(msg.type != I_GET_NONCE_RESPONSE && msg.type != I_GET_NONCE && msg.type != I_REQUEST_SIGNING &&
328+
msg.type != I_ID_REQUEST && msg.type != I_ID_RESPONSE &&
329+
msg.type != I_FIND_PARENT && msg.type != I_FIND_PARENT_RESPONSE))) {
330+
if (!mGetSigned(msg)) {
331+
debug(PSTR("Got unsigned message that should have been signed\n"));
332+
return false;
333+
}
320334
else if (!signer.verifyMsg(msg)) {
321335
debug(PSTR("Message verification failed\n"));
322336
return false; // This signed message has been tampered with!
@@ -383,10 +397,9 @@ boolean MySensor::process() {
383397
return false;
384398
} else if (type == I_GET_NONCE) {
385399
if (signer.getNonce(msg)) {
386-
sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_GET_NONCE_RESPONSE, false));
387-
} else {
388-
return false;
400+
sendRoute(build(msg, nc.nodeId, msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_GET_NONCE_RESPONSE, false));
389401
}
402+
return false; // Nonce exchange is an internal MySensor protocol message, no need to inform caller about this
390403
} else if (type == I_REQUEST_SIGNING) {
391404
if (msg.getBool()) {
392405
// We received an indicator that the sender require us to sign all messages we send to it
@@ -407,6 +420,9 @@ boolean MySensor::process() {
407420
else
408421
sendRoute(build(msg, nc.nodeId, msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(false));
409422
}
423+
return false; // Signing request is an internal MySensor protocol message, no need to inform caller about this
424+
} else if (type == I_GET_NONCE_RESPONSE) {
425+
return true; // Just pass along nonce silently (no need to call callback for these)
410426
} else if (sender == GATEWAY_ADDRESS) {
411427
bool isMetric;
412428

0 commit comments

Comments
 (0)