Skip to content

Commit 5b034cf

Browse files
committed
Merge pull request arduino#84 from fallberg/gw_sign
Support for gateways to request signed messages
2 parents 89076d5 + 79be69b commit 5b034cf

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)