From 02fbe536d4c8f9387bb17eeb4b45f664c154d672 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Wed, 16 Dec 2015 10:52:40 +0100 Subject: [PATCH] Signing infrastructure refactored Signing logic has now been centralized to MySigning.cpp in order to simplify maintenance and debugging. Debug prints have been extended and "demoted" to verbose level. To get signing related debug info, MY_DEBUG_VERBOSE will need to be defined. This fixes #278 --- libraries/MySensors/MySensor.h | 6 +- libraries/MySensors/core/MyMessage.h | 6 +- libraries/MySensors/core/MySensorCore.cpp | 12 +- libraries/MySensors/core/MySigning.cpp | 285 ++++++++++++++++++ libraries/MySensors/core/MySigning.h | 57 ++-- .../MySensors/core/MySigningAtsha204.cpp | 49 ++- .../MySensors/core/MySigningAtsha204Soft.cpp | 45 ++- libraries/MySensors/core/MyTransport.cpp | 143 +-------- libraries/MySensors/core/MyTransport.h | 3 - .../MySensors/drivers/ATSHA204/ATSHA204.h | 2 + libraries/sha204/sha204_library.h | 2 + 11 files changed, 395 insertions(+), 215 deletions(-) diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index c07402a..cff8ead 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -95,9 +95,11 @@ // SIGNING #if defined(MY_SIGNING_ATSHA204) || defined(MY_SIGNING_SOFT) - // SIGNING COMMON FUNCTIONS - #include "core/MySigning.cpp" #define MY_SIGNING_FEATURE +#endif +#include "core/MySigning.cpp" +#if defined(MY_SIGNING_FEATURE) + // SIGNING COMMON FUNCTIONS #if defined(MY_SIGNING_ATSHA204) && defined(MY_SIGNING_SOFT) #error Only one signing engine can be activated #endif diff --git a/libraries/MySensors/core/MyMessage.h b/libraries/MySensors/core/MyMessage.h index c40f995..a81073a 100644 --- a/libraries/MySensors/core/MyMessage.h +++ b/libraries/MySensors/core/MyMessage.h @@ -163,9 +163,9 @@ typedef enum { I_INCLUSION_MODE, I_CONFIG, I_FIND_PARENT, I_FIND_PARENT_RESPONSE, I_LOG_MESSAGE, I_CHILDREN, I_SKETCH_NAME, I_SKETCH_VERSION, I_REBOOT, I_GATEWAY_READY, - I_REQUEST_SIGNING, /*!< Indicates sender require signed messages (bool param) */ - I_GET_NONCE, /*!< Request for a nonce */ - I_GET_NONCE_RESPONSE, /*!< Payload is nonce data */ + I_REQUEST_SIGNING, /*!< Indicates sender require signed messages (bool param) */ + I_NONCE_REQUEST, /*!< Request for a nonce */ + I_NONCE_RESPONSE, /*!< Payload is nonce data */ I_HEARTBEAT, I_PRESENTATION, I_DISCOVER, I_DISCOVER_RESPONSE, I_HEARTBEAT_RESPONSE } mysensor_internal; diff --git a/libraries/MySensors/core/MySensorCore.cpp b/libraries/MySensors/core/MySensorCore.cpp index 2984513..9fea04d 100644 --- a/libraries/MySensors/core/MySensorCore.cpp +++ b/libraries/MySensors/core/MySensorCore.cpp @@ -62,15 +62,12 @@ static inline bool isValidParent( const uint8_t parent ) { void _begin() { #if !defined(MY_DISABLED_SERIAL) hwInit(); - #endif - - #if defined(MY_SIGNING_SOFT) - // initialize pseudo-RNG - randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN)); #endif debug(PSTR("Starting " MY_NODE_TYPE " (" MY_CAPABILIIES ", " LIBRARY_VERSION ")\n")); + signerInit(); + #if defined(MY_RADIO_FEATURE) _failedTransmissions = 0; @@ -107,11 +104,6 @@ void _begin() { #endif - #if defined(MY_SIGNING_FEATURE) - // Read out the signing requirements from EEPROM - hwReadConfigBlock((void*)_doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, sizeof(_doSign)); - #endif - #if defined(MY_LEDS_BLINKING_FEATURE) ledsInit(); #endif diff --git a/libraries/MySensors/core/MySigning.cpp b/libraries/MySensors/core/MySigning.cpp index ff5e3d1..c54f199 100644 --- a/libraries/MySensors/core/MySigning.cpp +++ b/libraries/MySensors/core/MySigning.cpp @@ -19,7 +19,292 @@ #include "MySigning.h" +#if defined(MY_DEBUG_VERBOSE) +#define SIGN_DEBUG(x,...) debug(x, ##__VA_ARGS__) +#else +#define SIGN_DEBUG(x,...) +#endif +#if defined(MY_SIGNING_REQUEST_SIGNATURES) && (!defined(MY_SIGNING_ATSHA204) && !defined(MY_SIGNING_SOFT)) +#error You have to pick either MY_SIGNING_ATSHA204 or MY_SIGNING_SOFT in order to require signatures! +#endif +#ifdef MY_SIGNING_FEATURE uint8_t _doSign[32]; // Bitfield indicating which sensors require signed communication MyMessage _msgSign; // Buffer for message to sign. +uint8_t _signingNonceStatus; +// Status when waiting for signing nonce in signerProcessInternal +enum { SIGN_WAITING_FOR_NONCE = 0, SIGN_OK = 1 }; + +// Macros for manipulating signing requirement table +#define DO_SIGN(node) (~_doSign[node>>3]&(1<>3]&=~(1<>3]|=(1< MY_VERIFICATION_TIMEOUT_MS) { + SIGN_DEBUG(PSTR("Timeout waiting for nonce!\n")); + return false; + } + if (_signingNonceStatus == SIGN_OK) { + // process() received a nonce and signerProcessInternal successfully signed the message + msg = _msgSign; // Write the signed message back + SIGN_DEBUG(PSTR("Message to send has been signed\n")); + } else { + SIGN_DEBUG(PSTR("Message to send could not be signed!\n")); + return false; + } + // After this point, only the 'last' member of the message structure is allowed to be altered if the + // message has been signed, or signature will become invalid and the message rejected by the receiver + } + } else if (_nc.nodeId == msg.sender) { + mSetSigned(msg, 0); // Message is not supposed to be signed, make sure it is marked unsigned + } +#else + (void)msg; +#endif // MY_SIGNING_FEATURE + return true; +} + +bool signerVerifyMsg(MyMessage &msg) { + bool verificationResult = true; + // Before processing message, reject unsigned messages if signing is required and check signature + // (if it is signed and addressed to us) + // Note that we do not care at all about any signature found if we do not require signing +#if defined(MY_SIGNING_FEATURE) && defined(MY_SIGNING_REQUEST_SIGNATURES) + // If we are a node, or we are a gateway and the sender require signatures + // and we are the destination... + if ((!MY_IS_GATEWAY || DO_SIGN(msg.sender)) && msg.destination == _nc.nodeId) { + // Internal messages of certain types are not verified + if (skipSign(msg)) { + verificationResult = true; + } + else if (!mGetSigned(msg)) { + // Got unsigned message that should have been signed + SIGN_DEBUG(PSTR("Message is not signed, but it should have been!\n")); + verificationResult = false; + } else { +#if defined(MY_SIGNING_SOFT) + verificationResult = signerAtsha204SoftVerifyMsg(msg); +#endif +#if defined(MY_SIGNING_ATSHA204) + verificationResult = signerAtsha204VerifyMsg(msg); +#endif + if (!verificationResult) { + SIGN_DEBUG(PSTR("Signature verification failed!\n")); + } + mSetSigned(msg,0); // Clear the sign-flag now as verification is completed + } + } +#else + (void)msg; +#endif // MY_SIGNING_REQUEST_SIGNATURES + return verificationResult; +} diff --git a/libraries/MySensors/core/MySigning.h b/libraries/MySensors/core/MySigning.h index 0c66096..d2595e5 100644 --- a/libraries/MySensors/core/MySigning.h +++ b/libraries/MySensors/core/MySigning.h @@ -364,8 +364,8 @@ * datasheet. * In the MySensors protocol, the following internal messagetypes handles signature requirements and nonce requests:
* @ref I_REQUEST_SIGNING
- * @ref I_GET_NONCE
- * @ref I_GET_NONCE_RESPONSE
+ * @ref I_NONCE_REQUEST
+ * @ref I_NONCE_RESPONSE
* * Also, the version field in the header has been reduced from 3 to 2 bits in order to fit a single bit to indicate that a message is signed. * @@ -484,29 +484,42 @@ typedef struct { } whitelist_entry_t; #endif -// Macros for manipulating signing requirement table -/** @brief Return 'true' if provided node ID is requiring signed messages */ -#define DO_SIGN(node) (~_doSign[node>>3]&(1<<(node%8))) -/** @brief Mark provided node ID to require signed messages in table */ -#define SET_SIGN(node) (_doSign[node>>3]&=~(1<<(node%8))) -/** @brief Mark provided node ID to not require signed messages in table */ -#define CLEAR_SIGN(node) (_doSign[node>>3]|=(1<<(node%8))) /** @brief Helper macro to determine the number of elements in a array */ #define NUM_OF(x) (sizeof(x)/sizeof(x[0])) /** - * @brief Stores signing identifier and a new nonce in provided message for signing operations. + * @brief Initializes signing infrastructure and associated backend. * - * All space in message payload buffer is used for signing identifier and nonce.
- * Returns @c false if subsystem is busy processing an ongoing signing operation.
- * If successful, this marks the start of a signing operation at the receiving side so - * implementation is expected to do any necessary initializations within this call. - * \n@b Usage: This function is typically called as action when receiving a @ref I_GET_NONCE message. - * - * @param msg The message to put the nonce in. - * @returns @c true if nonce is successfully put in provided message. + * This function makes sure that the internal states of the signing infrastructure + * is set to a known initial state. + * \n@b Usage: This fuction should be called before any signing related operations take place. */ -bool signerGetNonce(MyMessage &msg); +void signerInit(void); + +/** + * @brief Does signing specific presentation for a node. + * + * This function makes sure any signing related presentation info is shared with the gateway. + * The presentation of the gateways signing preferences is done in @ref signerProcessInternal(). + * \n@b Usage: This function should be called by the presentation routine of the mysensors library. + * There is no need to call this directly from a sketch. + * + * @param msg Message buffer to use. + */ +void signerPresentation(MyMessage &msg); + +/** + * @brief Manages internal signing message handshaking. + * + * This function takes care of signing related message handshaknig such as nonce exchange. + * \n@b Usage: This function should be called by the incoming message handler before any further message + * processing is performed on internal messages. This function should only be called for @ref C_INTERNAL class + * messages. + * + * @param msg Message buffer to process. + * @returns @c true if caller should stop further message processing. + */ +bool signerProcessInternal(MyMessage &msg); /** * @brief Check timeout of verification session. @@ -525,7 +538,7 @@ bool signerCheckTimer(void); * Returns @c false if signing identifier found in message is not supported by the used backend.
* If successful, this marks the start of a signing operation at the sending side so * implementation is expected to do any necessary initializations within this call. - * \n@b Usage: This function is typically called as action when receiving a @ref I_GET_NONCE_RESPONSE + * \n@b Usage: This function is typically called as action when receiving a @ref I_NONCE_RESPONSE * message. * * @param msg The message to get the nonce from. @@ -537,13 +550,13 @@ bool signerPutNonce(MyMessage &msg); * @brief Signs provided message. All remaining space in message payload buffer is used for * signing identifier and signature. * - * Nonce used for signature calculation is the one generated previously using @ref signerGetNonce().
+ * Nonce used for signature calculation is the one generated previously within @ref signerProcessInternal().
* Nonce will be cleared when this function is called to prevent re-use of nonce.
* Returns @c false if subsystem is busy processing an ongoing signing operation.
* Returns @c false if not two bytes or more of free payload space is left in provided message.
* This ends a signing operation at the sending side so implementation is expected to do any * deinitializations and enter a power saving state within this call. - * \n@b Usage: This function is typically called as action when receiving a @ref I_GET_NONCE_RESPONSE + * \n@b Usage: This function is typically called as action when receiving a @ref I_NONCE_RESPONSE * message and after @ref signerPutNonce() has successfully been executed. * * @param msg The message to sign. diff --git a/libraries/MySensors/core/MySigningAtsha204.cpp b/libraries/MySensors/core/MySigningAtsha204.cpp index 218c22f..87cf84e 100644 --- a/libraries/MySensors/core/MySigningAtsha204.cpp +++ b/libraries/MySensors/core/MySigningAtsha204.cpp @@ -29,7 +29,7 @@ #define SIGNING_IDENTIFIER (1) -// Define MY_DEBUG in your sketch to enable signing backend debugprints +// Define MY_DEBUG_VERBOSE in your sketch to enable signing backend debugprints ATSHA204Class atsha204(MY_SIGNING_ATSHA204_PIN); unsigned long _signing_timestamp; @@ -43,11 +43,11 @@ uint8_t _singning_tx_buffer[SHA204_CMD_SIZE_MAX]; const whitelist_entry_t _signing_whitelist[] = MY_SIGNING_NODE_WHITELISTING; #endif -void signerCalculateSignature(MyMessage &msg); -uint8_t* signerSha256(const uint8_t* data, size_t sz); +static void signerCalculateSignature(MyMessage &msg); +static uint8_t* signerSha256(const uint8_t* data, size_t sz); -#ifdef MY_DEBUG +#ifdef MY_DEBUG_VERBOSE static char i2h(uint8_t i) { uint8_t k = i & 0x0F; @@ -57,8 +57,7 @@ static char i2h(uint8_t i) return 'A' + k - 10; } -static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, uint8_t sz) -{ +static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, uint8_t sz) { static char printBuffer[300]; #ifdef MY_GATEWAY_FEATURE // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) @@ -86,7 +85,20 @@ static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, #define DEBUG_SIGNING_PRINTBUF(str, buf, sz) #endif -bool signerGetNonce(MyMessage &msg) { +bool signerAtsha204CheckTimer(void) { + if (_signing_verification_ongoing) { + if (millis() < _signing_timestamp || millis() > _signing_timestamp + MY_VERIFICATION_TIMEOUT_MS) { + DEBUG_SIGNING_PRINTBUF(F("Verification timeout"), NULL, 0); + // Purge nonce + memset(_signing_current_nonce, 0x00, NONCE_NUMIN_SIZE_PASSTHROUGH); + _signing_verification_ongoing = false; + return false; + } + } + return true; +} + +bool signerAtsha204GetNonce(MyMessage &msg) { DEBUG_SIGNING_PRINTBUF(F("Signing backend: ATSHA204"), NULL, 0); // Generate random number for use as nonce // We used a basic whitening technique that takes the first byte of a new random value and builds up a 32-byte random value @@ -118,20 +130,7 @@ bool signerGetNonce(MyMessage &msg) { return true; } -bool signerCheckTimer() { - if (_signing_verification_ongoing) { - if (millis() < _signing_timestamp || millis() > _signing_timestamp + MY_VERIFICATION_TIMEOUT_MS) { - DEBUG_SIGNING_PRINTBUF(F("Verification timeout"), NULL, 0); - // Purge nonce - memset(_signing_current_nonce, 0x00, NONCE_NUMIN_SIZE_PASSTHROUGH); - _signing_verification_ongoing = false; - return false; - } - } - return true; -} - -bool signerPutNonce(MyMessage &msg) { +bool signerAtsha204PutNonce(MyMessage &msg) { DEBUG_SIGNING_PRINTBUF(F("Signing backend: ATSHA204"), NULL, 0); if (((uint8_t*)msg.getCustom())[0] != SIGNING_IDENTIFIER) { DEBUG_SIGNING_PRINTBUF(F("Incorrect signing identifier"), NULL, 0); @@ -144,7 +143,7 @@ bool signerPutNonce(MyMessage &msg) { return true; } -bool signerSignMsg(MyMessage &msg) { +bool signerAtsha204SignMsg(MyMessage &msg) { // If we cannot fit any signature in the message, refuse to sign it if (mGetLength(msg) > MAX_PAYLOAD-2) { DEBUG_SIGNING_PRINTBUF(F("Message too large"), NULL, 0); @@ -174,7 +173,7 @@ bool signerSignMsg(MyMessage &msg) { return true; } -bool signerVerifyMsg(MyMessage &msg) { +bool signerAtsha204VerifyMsg(MyMessage &msg) { if (!_signing_verification_ongoing) { DEBUG_SIGNING_PRINTBUF(F("No active verification session"), NULL, 0); return false; @@ -226,7 +225,7 @@ bool signerVerifyMsg(MyMessage &msg) { } // Helper to calculate signature of msg (returned in _singning_rx_buffer[SHA204_BUFFER_POS_DATA]) -void signerCalculateSignature(MyMessage &msg) { +static void signerCalculateSignature(MyMessage &msg) { memset(_signing_temp_message, 0, 32); memcpy(_signing_temp_message, (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); @@ -259,7 +258,7 @@ void signerCalculateSignature(MyMessage &msg) { // Helper to calculate a generic SHA256 digest of provided buffer (only supports one block) // The pointer to the hash is returned, but the hash is also stored in _singning_rx_buffer[SHA204_BUFFER_POS_DATA]) -uint8_t* signerSha256(const uint8_t* data, size_t sz) { +static uint8_t* signerSha256(const uint8_t* data, size_t sz) { // Initiate SHA256 calculator (void)atsha204.sha204m_execute(SHA204_SHA, SHA_INIT, 0, 0, NULL, SHA_COUNT_SHORT, _singning_tx_buffer, SHA_RSP_SIZE_SHORT, _singning_rx_buffer); diff --git a/libraries/MySensors/core/MySigningAtsha204Soft.cpp b/libraries/MySensors/core/MySigningAtsha204Soft.cpp index c4152f6..4451e78 100644 --- a/libraries/MySensors/core/MySigningAtsha204Soft.cpp +++ b/libraries/MySensors/core/MySigningAtsha204Soft.cpp @@ -33,7 +33,7 @@ #define SIGNING_IDENTIFIER (1) -// Define MY_DEBUG in your sketch to enable signing backend debugprints +// Define MY_DEBUG_VERBOSE in your sketch to enable signing backend debugprints Sha256Class _signing_sha256; unsigned long _signing_timestamp; @@ -48,9 +48,9 @@ uint8_t _signing_hmac[32]; const whitelist_entry_t _signing_whitelist[] = MY_SIGNING_NODE_WHITELISTING; #endif -void signerCalculateSignature(MyMessage &msg); +static void signerCalculateSignature(MyMessage &msg); -#ifdef MY_DEBUG +#ifdef MY_DEBUG_VERBOSE static char i2h(uint8_t i) { uint8_t k = i & 0x0F; @@ -60,8 +60,7 @@ static char i2h(uint8_t i) return 'A' + k - 10; } -static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, uint8_t sz) -{ +static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, uint8_t sz) { static char printBuffer[300]; #ifdef MY_GATEWAY_FEATURE // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) @@ -89,7 +88,20 @@ static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, #define DEBUG_SIGNING_PRINTBUF(str, buf, sz) #endif -bool signerGetNonce(MyMessage &msg) { +bool signerAtsha204SoftCheckTimer(void) { + if (_signing_verification_ongoing) { + if (millis() < _signing_timestamp || millis() > _signing_timestamp + MY_VERIFICATION_TIMEOUT_MS) { + DEBUG_SIGNING_PRINTBUF(F("Verification timeout"), NULL, 0); + // Purge nonce + memset(_signing_current_nonce, 0xAA, 32); + _signing_verification_ongoing = false; + return false; + } + } + return true; +} + +bool signerAtsha204SoftGetNonce(MyMessage &msg) { DEBUG_SIGNING_PRINTBUF(F("Signing backend: ATSHA204Soft"), NULL, 0); // We used a basic whitening technique that takes the first byte of a new random value and builds up a 32-byte random value @@ -118,20 +130,7 @@ bool signerGetNonce(MyMessage &msg) { return true; } -bool signerCheckTimer() { - if (_signing_verification_ongoing) { - if (millis() < _signing_timestamp || millis() > _signing_timestamp + MY_VERIFICATION_TIMEOUT_MS) { - DEBUG_SIGNING_PRINTBUF(F("Verification timeout"), NULL, 0); - // Purge nonce - memset(_signing_current_nonce, 0xAA, 32); - _signing_verification_ongoing = false; - return false; - } - } - return true; -} - -bool signerPutNonce(MyMessage &msg) { +bool signerAtsha204SoftPutNonce(MyMessage &msg) { DEBUG_SIGNING_PRINTBUF(F("Signing backend: ATSHA204Soft"), NULL, 0); if (((uint8_t*)msg.getCustom())[0] != SIGNING_IDENTIFIER) { DEBUG_SIGNING_PRINTBUF(F("Incorrect signing identifier"), NULL, 0); @@ -144,7 +143,7 @@ bool signerPutNonce(MyMessage &msg) { return true; } -bool signerSignMsg(MyMessage &msg) { +bool signerAtsha204SoftSignMsg(MyMessage &msg) { // If we cannot fit any signature in the message, refuse to sign it if (mGetLength(msg) > MAX_PAYLOAD-2) { DEBUG_SIGNING_PRINTBUF(F("Message too large"), NULL, 0); @@ -176,7 +175,7 @@ bool signerSignMsg(MyMessage &msg) { return true; } -bool signerVerifyMsg(MyMessage &msg) { +bool signerAtsha204SoftVerifyMsg(MyMessage &msg) { if (!_signing_verification_ongoing) { DEBUG_SIGNING_PRINTBUF(F("No active verification session"), NULL, 0); return false; @@ -231,7 +230,7 @@ bool signerVerifyMsg(MyMessage &msg) { } // Helper to calculate signature of msg (returned in hmac) -void signerCalculateSignature(MyMessage &msg) { +static void signerCalculateSignature(MyMessage &msg) { memset(_signing_temp_message, 0, 32); memcpy(_signing_temp_message, (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); DEBUG_SIGNING_PRINTBUF(F("Message to process: "), (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); diff --git a/libraries/MySensors/core/MyTransport.cpp b/libraries/MySensors/core/MyTransport.cpp index 4c3e796..f0a2723 100644 --- a/libraries/MySensors/core/MyTransport.cpp +++ b/libraries/MySensors/core/MyTransport.cpp @@ -23,10 +23,6 @@ bool _autoFindParent; uint8_t _failedTransmissions; -#ifdef MY_SIGNING_FEATURE - uint8_t _signingNonceStatus; -#endif - #ifdef MY_OTA_FIRMWARE_FEATURE SPIFlash _flash(MY_OTA_FLASH_SS, MY_OTA_FLASH_JDECID); NodeFirmwareConfig _fc; @@ -70,9 +66,7 @@ inline void transportProcess() { return; } - #ifdef MY_SIGNING_FEATURE (void)signerCheckTimer(); // Manage signing timeout - #endif uint8_t payloadLength = transportReceive((uint8_t *)&_msg); (void)payloadLength; //until somebody makes use of it @@ -86,34 +80,12 @@ inline void transportProcess() { uint8_t destination = _msg.destination; - #ifdef MY_SIGNING_FEATURE - // Before processing message, reject unsigned messages if signing is required and check signature (if it is signed and addressed to us) - // 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) - #ifdef MY_SIGNING_REQUEST_SIGNATURES - - if ((!MY_IS_GATEWAY || DO_SIGN(sender)) && - destination == _nc.nodeId && - !mGetAck(_msg) && - (mGetCommand(_msg) != C_INTERNAL || - (type != I_GET_NONCE_RESPONSE && type != I_GET_NONCE && type != I_REQUEST_SIGNING && - type != I_ID_REQUEST && type != I_ID_RESPONSE && - type != I_FIND_PARENT && type != I_FIND_PARENT_RESPONSE && - type != I_HEARTBEAT && type != I_HEARTBEAT_RESPONSE))) { - if (!mGetSigned(_msg)) { - // Got unsigned message that should have been signed - debug(PSTR("no sign\n")); - ledBlinkErr(1); - return; - } - else if (!signerVerifyMsg(_msg)) { - debug(PSTR("verify fail\n")); - ledBlinkErr(1); - return; // This signed message has been tampered with! - } - } - #endif - #endif - + // Reject massages that do not pass verification + if (!signerVerifyMsg(_msg)) { + debug(PSTR("verify fail\n")); + ledBlinkErr(1); + return; + } if (destination == _nc.nodeId) { debug(PSTR("read: %d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d:%s\n"), @@ -138,7 +110,6 @@ inline void transportProcess() { if (destination == _nc.nodeId) { // This message is addressed to this node - mSetSigned(_msg,0); // Clear the sign-flag now as verification is completed // prevent buffer overflow by limiting max. possible message length (5 bits=31 bytes max) to MAX_PAYLOAD (25 bytes) mSetLength(_msg, min(mGetLength(_msg),MAX_PAYLOAD)); // null terminate data @@ -163,6 +134,10 @@ inline void transportProcess() { } if (command == C_INTERNAL) { + // Process signing related internal messages + if (signerProcessInternal(_msg)) { + return; // Signer processing indicated no further action needed + } if (type == I_FIND_PARENT_RESPONSE) { if (_autoFindParent) { // We've received a reply to a FIND_PARENT message. Check if the distance is @@ -183,44 +158,6 @@ inline void transportProcess() { } } return; - #ifdef MY_SIGNING_FEATURE - } else if (type == I_GET_NONCE) { - if (signerGetNonce(_msg)) { - _sendRoute(build(_msg, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_GET_NONCE_RESPONSE, false)); - } - return; // Nonce exchange is an internal MySensor protocol message, no need to inform caller about this - } else if (type == I_REQUEST_SIGNING) { - if (_msg.getBool()) { - // We received an indicator that the sender require us to sign all messages we send to it - SET_SIGN(sender); - } else { - // We received an indicator that the sender does not require us to sign all messages we send to it - CLEAR_SIGN(sender); - } - // Save updated table - hwWriteConfigBlock((void*)_doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, sizeof(_doSign)); - - // Inform sender about our preference if we are a gateway, but only require signing if the sender required signing - // We do not currently want a gateway to require signing from all nodes in a network just because it wants one node - // to sign it's messages - #if defined (MY_GATEWAY_FEATURE) - #ifdef MY_SIGNING_REQUEST_SIGNATURES - if (DO_SIGN(sender)) - _sendRoute(build(_msg, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set((uint8_t)true)); - else - _sendRoute(build(_msg, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set((uint8_t)false)); - #else - _sendRoute(build(_msg, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set((uint8_t)false)); - #endif - #endif - return; // Signing request is an internal MySensor protocol message, no need to inform caller about this - } else if (type == I_GET_NONCE_RESPONSE) { - // Proceed with signing if nonce has been received - if (signerPutNonce(_msg) && signerSignMsg(_msgSign)) { - _signingNonceStatus = SIGN_OK; - } - return; // Just pass along nonce silently (no need to call callback for these) - #endif } else if (sender == GATEWAY_ADDRESS) { if (type == I_ID_RESPONSE && _nc.nodeId == AUTO) { _nc.nodeId = _msg.getByte(); @@ -414,47 +351,10 @@ boolean transportSendRoute(MyMessage &message) { mSetVersion(message, PROTOCOL_VERSION); - #ifdef MY_SIGNING_FEATURE - uint8_t type = message.type; - // 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 - if (DO_SIGN(message.destination) && message.sender == _nc.nodeId && !mGetAck(message) && - (mGetCommand(message) != C_INTERNAL || - (type != I_GET_NONCE && type != I_GET_NONCE_RESPONSE && type != I_REQUEST_SIGNING && - type != I_ID_REQUEST && type != I_ID_RESPONSE && - type != I_FIND_PARENT && type != I_FIND_PARENT_RESPONSE && - type != I_HEARTBEAT && type != I_HEARTBEAT_RESPONSE))) { - // Send nonce-request - _signingNonceStatus=SIGN_WAITING_FOR_NONCE; - if (!_sendRoute(build(_msgTmp, _nc.nodeId, message.destination, message.sensor, C_INTERNAL, I_GET_NONCE, false).set(""))) { - debug(PSTR("nonce tr err\n")); - return false; - } - // We have to wait for the nonce to arrive before we can sign our original message - // Other messages could come in-between. We trust process() takes care of them - unsigned long enter = hwMillis(); - _msgSign = message; // Copy the message to sign since message buffer might be touched in process() - - while (hwMillis() - enter < MY_VERIFICATION_TIMEOUT_MS && _signingNonceStatus==SIGN_WAITING_FOR_NONCE) { - _process(); - } - if (hwMillis() - enter > MY_VERIFICATION_TIMEOUT_MS) { - debug(PSTR("nonce tmo\n")); - ledBlinkErr(1); - return false; - } - if (_signingNonceStatus == SIGN_OK) { - message = _msgSign; // Write the signed message back - } else { - debug(PSTR("sign fail\n")); - ledBlinkErr(1); - return false; - } - // After this point, only the 'last' member of the message structure is allowed to be altered if the message has been signed, - // or signature will become invalid and the message rejected by the receiver - } else if (_nc.nodeId == message.sender) { - mSetSigned(message, 0); // Message is not supposed to be signed, make sure it is marked unsigned - } - #endif + if (!signerSignMsg(message)) { + debug(PSTR("sign fail\n")); + ledBlinkErr(1); + } #if !defined(MY_REPEATER_FEATURE) @@ -552,19 +452,8 @@ void transportPresentNode() { // Present node and request config #ifndef MY_GATEWAY_FEATURE if (_nc.nodeId != AUTO) { - #ifdef MY_SIGNING_FEATURE - // Notify gateway (and possibly controller) about the signing preferences of this node - #if defined(MY_SIGNING_REQUEST_SIGNATURES) - _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(true)); - // If we do require signing, wait for the gateway to tell us how it prefer us to transmit our messages - wait(2000); - #else - _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(false)); - #endif - #else - // We do not support signing, make sure gateway knows this - _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(false)); - #endif + // Send signing preferences for this node + signerPresentation(_msg); // Send presentation for this radio node #ifdef MY_REPEATER_FEATURE diff --git a/libraries/MySensors/core/MyTransport.h b/libraries/MySensors/core/MyTransport.h index 18be525..e23869e 100644 --- a/libraries/MySensors/core/MyTransport.h +++ b/libraries/MySensors/core/MyTransport.h @@ -41,9 +41,6 @@ // Search for a new parent node after this many transmission failures #define SEARCH_FAILURES 5 -// Status when waiting for signing nonce in process -enum { SIGN_WAITING_FOR_NONCE = 0, SIGN_OK = 1 }; - // FW config structure, stored in eeprom typedef struct { diff --git a/libraries/MySensors/drivers/ATSHA204/ATSHA204.h b/libraries/MySensors/drivers/ATSHA204/ATSHA204.h index 59a9f0e..c7034bf 100644 --- a/libraries/MySensors/drivers/ATSHA204/ATSHA204.h +++ b/libraries/MySensors/drivers/ATSHA204/ATSHA204.h @@ -199,7 +199,9 @@ #define SHA204_COMMAND_EXEC_MAX ((uint8_t) (69.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) //! maximum command delay #define SHA204_CMD_SIZE_MIN ((uint8_t) 7) //! minimum number of bytes in command (from count byte to second CRC byte) +#ifndef SHA204_CMD_SIZE_MAX #define SHA204_CMD_SIZE_MAX ((uint8_t) SHA_COUNT_LONG) //! maximum size of command packet (SHA) +#endif #define SHA204_CRC_SIZE ((uint8_t) 2) //! number of CRC bytes #define SHA204_BUFFER_POS_STATUS (1) //! buffer index of status byte in status response #define SHA204_BUFFER_POS_DATA (1) //! buffer index of first data byte in data response diff --git a/libraries/sha204/sha204_library.h b/libraries/sha204/sha204_library.h index fe12392..c22f9ed 100644 --- a/libraries/sha204/sha204_library.h +++ b/libraries/sha204/sha204_library.h @@ -259,7 +259,9 @@ #define SHA204_COMMAND_EXEC_MAX ((uint8_t) (69.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) //! maximum command delay #define SHA204_CMD_SIZE_MIN ((uint8_t) 7) //! minimum number of bytes in command (from count byte to second CRC byte) +#ifndef SHA204_CMD_SIZE_MAX #define SHA204_CMD_SIZE_MAX ((uint8_t) 84) //! maximum size of command packet (CheckMac) +#endif #define SHA204_CRC_SIZE ((uint8_t) 2) //! number of CRC bytes #define SHA204_BUFFER_POS_STATUS (1) //! buffer index of status byte in status response #define SHA204_BUFFER_POS_DATA (1) //! buffer index of first data byte in data response