From 91985beb9d024e7a1a4c92eeb331f9d27f887d2e Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Thu, 7 Jan 2016 23:11:21 +0100 Subject: [PATCH 01/10] Bumped version to 2.0.0-beta Considering the magnitude of the delta between master and development branch currently, 2.0.0-beta apperas to be a more realistic version than 1.6.0-beta. --- libraries/MySensors/core/Version.h | 2 +- libraries/MySensors/library.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/MySensors/core/Version.h b/libraries/MySensors/core/Version.h index db9db44..fce3bc7 100644 --- a/libraries/MySensors/core/Version.h +++ b/libraries/MySensors/core/Version.h @@ -6,6 +6,6 @@ #ifndef Version_h #define Version_h -#define LIBRARY_VERSION "1.6.0-beta" +#define LIBRARY_VERSION "2.0.0-beta" #endif diff --git a/libraries/MySensors/library.properties b/libraries/MySensors/library.properties index db72528..60d1ce7 100644 --- a/libraries/MySensors/library.properties +++ b/libraries/MySensors/library.properties @@ -1,5 +1,5 @@ name=MySensors -version=1.6.0 +version=2.0.0-beta author=The MySensors Team maintainer=The MySensors Team sentence=Home Automation Framework From 866e7cf08b0dc55c0b0d8549e1c7ee631be8c220 Mon Sep 17 00:00:00 2001 From: tekka007 Date: Tue, 5 Jan 2016 14:48:23 +0100 Subject: [PATCH 02/10] HW-independent ClearEepromConfig, substitutes #314 --- libraries/MySensors/MySensor.h | 24 +++++++++++-------- .../ClearEepromConfig/ClearEepromConfig.ino | 10 ++++---- libraries/MySensors/keywords.txt | 3 ++- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index d795655..c07402a 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -48,8 +48,10 @@ //#undef F //#define F(x) (x) #include "core/MyHwESP8266.cpp" - // For ESP8266, we always enable gateway feature - #define MY_GATEWAY_ESP8266 + // Enable gateway feature + #if !defined(MY_CORE_ONLY) + #define MY_GATEWAY_ESP8266 + #endif #elif defined(ARDUINO_ARCH_AVR) #include "core/MyHwATMega328.cpp" #elif defined(ARDUINO_ARCH_SAMD) @@ -219,22 +221,24 @@ #undef MY_INCLUSION_BUTTON_FEATURE #endif -#if !defined(MY_GATEWAY_FEATURE) && !defined(MY_RADIO_FEATURE) - #error No forward link or gateway feature activated. This means nowhere to send messages! Pretty pointless. +#if !defined(MY_CORE_ONLY) + #if !defined(MY_GATEWAY_FEATURE) && !defined(MY_RADIO_FEATURE) + #error No forward link or gateway feature activated. This means nowhere to send messages! Pretty pointless. + #endif #endif - #include "core/MyCapabilities.h" #include "core/MyMessage.cpp" #include "core/MySensorCore.cpp" #include -#if defined(MY_GATEWAY_ESP8266) - #include "core/MyMainESP8266.cpp" -#else - #include "core/MyMainDefault.cpp" +#if !defined(MY_CORE_ONLY) + #if defined(MY_GATEWAY_ESP8266) + #include "core/MyMainESP8266.cpp" + #else + #include "core/MyMainDefault.cpp" + #endif #endif - #endif diff --git a/libraries/MySensors/examples/ClearEepromConfig/ClearEepromConfig.ino b/libraries/MySensors/examples/ClearEepromConfig/ClearEepromConfig.ino index fffc4f9..272bf43 100644 --- a/libraries/MySensors/examples/ClearEepromConfig/ClearEepromConfig.ino +++ b/libraries/MySensors/examples/ClearEepromConfig/ClearEepromConfig.ino @@ -23,16 +23,18 @@ * This sketch clears radioId, relayId and other routing information in EEPROM back to factory default * */ +// load core modules only +#define MY_CORE_ONLY -#include #include +#include void setup() { Serial.begin(MY_BAUD_RATE); Serial.println("Started clearing. Please wait..."); - for (int i=0;i<512;i++) { - EEPROM.write(i, 0xff); + for (int i=0;i Date: Mon, 11 Jan 2016 21:27:40 +0100 Subject: [PATCH 03/10] Added MY_CORE_ONLY flag to MySensors.h --- libraries/MySensors/MyConfig.h | 3 +++ libraries/MySensors/keywords.txt | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index d47f22a..ac9d1df 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -42,6 +42,9 @@ // Enable this in sketch if you want to use TX(1), RX(0) as normal I/O pin //#define MY_DISABLED_SERIAL +// Enable MY_CORE_ONLY flag if you want to use core functions without loading the framework +//#define MY_CORE_ONLY + // Turn off debug if serial pins is used for other stuff #ifdef MY_DISABLED_SERIAL #undef MY_DEBUG diff --git a/libraries/MySensors/keywords.txt b/libraries/MySensors/keywords.txt index a670de7..3ee0f8a 100644 --- a/libraries/MySensors/keywords.txt +++ b/libraries/MySensors/keywords.txt @@ -31,6 +31,7 @@ smartSleep KEYWORD2 ####################################### AUTO LITERAL1 MY_DEBUG LITERAL1 +MY_CORE_ONLY LITERAL1 MY_REPEATER_FEATURE LITERAL1 MY_RADIO_NRF24 LITERAL1 MY_RADIO_RFM69 LITERAL1 @@ -109,5 +110,4 @@ MY_GATEWAY_MQTT_CLIENT LITERAL1 MY_DISABLE_REMOTE_RESET LITERAL1 MY_RS485_DE_PIN LITERAL1 MY_SIGNING_REQUEST_SIGNATURES LITERAL1 -MY_SMART_SLEEP_WAIT_DURATION LITERAL1 -MY_CORE_ONLY LITERAL1 \ No newline at end of file +MY_SMART_SLEEP_WAIT_DURATION LITERAL1 \ No newline at end of file From b4879f0dced0e8b912bb11b918f035b8a28c520b Mon Sep 17 00:00:00 2001 From: tekka007 Date: Mon, 11 Jan 2016 21:47:18 +0100 Subject: [PATCH 04/10] void unused parameter --- libraries/MySensors/core/MySensorCore.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/MySensors/core/MySensorCore.cpp b/libraries/MySensors/core/MySensorCore.cpp index 809a32e..2984513 100644 --- a/libraries/MySensors/core/MySensorCore.cpp +++ b/libraries/MySensors/core/MySensorCore.cpp @@ -190,6 +190,9 @@ ControllerConfig getConfig() { boolean _sendRoute(MyMessage &message) { // increment heartbeat counter _heartbeat++; + #if defined(MY_CORE_ONLY) + (void)message; + #endif #if defined(MY_GATEWAY_FEATURE) if (message.destination == _nc.nodeId) { // This is a message sent from a sensor attached on the gateway node. From 02fbe536d4c8f9387bb17eeb4b45f664c154d672 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Wed, 16 Dec 2015 10:52:40 +0100 Subject: [PATCH 05/10] 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 From 5ecf146f15ad5beecadd381484e35f5fe8b32744 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Thu, 31 Dec 2015 15:15:54 +0100 Subject: [PATCH 06/10] Sha256 calculator for library use The signing infrastructure now supports calculating sha256. This feature does not require signing support to be activated. Fixes #315 --- libraries/MySensors/MySensor.h | 2 +- libraries/MySensors/core/MySigning.cpp | 20 ++++++++++++++ libraries/MySensors/core/MySigning.h | 27 +++++++++++++++++++ libraries/MySensors/drivers/ATSHA204/sha256.h | 2 +- 4 files changed, 49 insertions(+), 2 deletions(-) diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index cff8ead..2833f5a 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -98,6 +98,7 @@ #define MY_SIGNING_FEATURE #endif #include "core/MySigning.cpp" +#include "drivers/ATSHA204/sha256.cpp" #if defined(MY_SIGNING_FEATURE) // SIGNING COMMON FUNCTIONS #if defined(MY_SIGNING_ATSHA204) && defined(MY_SIGNING_SOFT) @@ -109,7 +110,6 @@ #include "drivers/ATSHA204/ATSHA204.cpp" #elif defined(MY_SIGNING_SOFT) #include "core/MySigningAtsha204Soft.cpp" - #include "drivers/ATSHA204/sha256.cpp" #endif #endif diff --git a/libraries/MySensors/core/MySigning.cpp b/libraries/MySensors/core/MySigning.cpp index c54f199..6e95b4a 100644 --- a/libraries/MySensors/core/MySigning.cpp +++ b/libraries/MySensors/core/MySigning.cpp @@ -18,6 +18,7 @@ */ #include "MySigning.h" +#include "drivers/ATSHA204/sha256.h" #if defined(MY_DEBUG_VERBOSE) #define SIGN_DEBUG(x,...) debug(x, ##__VA_ARGS__) @@ -308,3 +309,22 @@ bool signerVerifyMsg(MyMessage &msg) { #endif // MY_SIGNING_REQUEST_SIGNATURES return verificationResult; } + +static uint8_t sha256_hash[32]; +Sha256Class _soft_sha256; + +void signerSha256Init(void) { + memset(sha256_hash, 0, 32); + _soft_sha256.init(); +} + +void signerSha256Update(const uint8_t* data, size_t sz) { + for (size_t i = 0; i < sz; i++) { + _soft_sha256.write(data[i]); + } +} + +uint8_t* signerSha256Final(void) { + memcpy(sha256_hash, _soft_sha256.result(), 32); + return sha256_hash; +} diff --git a/libraries/MySensors/core/MySigning.h b/libraries/MySensors/core/MySigning.h index d2595e5..4f69c81 100644 --- a/libraries/MySensors/core/MySigning.h +++ b/libraries/MySensors/core/MySigning.h @@ -581,5 +581,32 @@ bool signerSignMsg(MyMessage &msg); */ bool signerVerifyMsg(MyMessage &msg); +/** + * @brief Initialize a hash calculation session. + * + * Any ongoing calculation session will be terminated/reset. + */ +void signerSha256Init(void); + +/** + * @brief Add data to an ongoing hash calculation session. + * + * More data can be added by repeated calls to this function. + * + * @param data Buffer with data to add. + * @param sz Size of data buffer. + */ +void signerSha256Update(const uint8_t* data, size_t sz); + +/** + * @brief Finalize an ongong hash calculation session and return the hash. + * + * The returned hash size is always 32 bytes. Buffer can be assumed to be valid + * until @ref signerSha256Init() is called again. + * + * @returns Buffer with 32-byte hash. + */ +uint8_t* signerSha256Final(void); + #endif /** @}*/ \ No newline at end of file diff --git a/libraries/MySensors/drivers/ATSHA204/sha256.h b/libraries/MySensors/drivers/ATSHA204/sha256.h index c0e3ef9..730e11d 100644 --- a/libraries/MySensors/drivers/ATSHA204/sha256.h +++ b/libraries/MySensors/drivers/ATSHA204/sha256.h @@ -23,7 +23,7 @@ class Sha256Class void initHmac(const uint8_t* secret, int secretLength); uint8_t* result(void); uint8_t* resultHmac(void); - virtual void write(uint8_t); + void write(uint8_t); private: void pad(); void addUncounted(uint8_t data); From ff015dd3730d892400a0e7c7a72c6858e3b2f7c6 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sat, 2 Jan 2016 14:55:41 +0100 Subject: [PATCH 07/10] Signing whitelisting rewritten Whitelisting is now supported by all nodes that support signing, while only nodes that define a whitelist with MY_SIGNING_NODE_WHITELISTING will check signatures against a whitelist. This allows a single node in a network to have a whitelist without require all nodes that communicate it to be configured for whitelisting. The node will publish its whitelisting preferences to the gateway together with its signing preferences. In other words; whitelisting is now working as signing requirements does. A node that use whitelisting will reject any message (signed or unsigned) from nodes not present in its whitelist. Fixes #279 --- libraries/MySensors/core/MyMessage.h | 6 +- libraries/MySensors/core/MySensorCore.h | 3 +- libraries/MySensors/core/MySigning.cpp | 125 ++++++++++++------ libraries/MySensors/core/MySigning.h | 44 +++--- .../MySensors/core/MySigningAtsha204.cpp | 24 ++-- .../MySensors/core/MySigningAtsha204Soft.cpp | 30 +++-- 6 files changed, 149 insertions(+), 83 deletions(-) diff --git a/libraries/MySensors/core/MyMessage.h b/libraries/MySensors/core/MyMessage.h index a81073a..3ed57ed 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_NONCE_REQUEST, /*!< Request for a nonce */ - I_NONCE_RESPONSE, /*!< Payload is nonce data */ + I_SIGNING_PRESENTATION, /*!< Provides signing related preferences (first byte is preference version) */ + 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.h b/libraries/MySensors/core/MySensorCore.h index 4d2c92e..6400373 100644 --- a/libraries/MySensors/core/MySensorCore.h +++ b/libraries/MySensors/core/MySensorCore.h @@ -52,7 +52,8 @@ #define EEPROM_FIRMWARE_BLOCKS_ADDRESS (EEPROM_FIRMWARE_VERSION_ADDRESS+2) #define EEPROM_FIRMWARE_CRC_ADDRESS (EEPROM_FIRMWARE_BLOCKS_ADDRESS+2) #define EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS (EEPROM_FIRMWARE_CRC_ADDRESS+2) -#define EEPROM_LOCAL_CONFIG_ADDRESS (EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS+32) // First free address for sketch static configuration +#define EEPROM_WHITELIST_REQUIREMENT_TABLE_ADDRESS (EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS+32) +#define EEPROM_LOCAL_CONFIG_ADDRESS (EEPROM_WHITELIST_REQUIREMENT_TABLE_ADDRESS+32) // First free address for sketch static configuration // This is the nodeId for sensor net gateway receiver sketch (where all sensors should send their data). #define GATEWAY_ADDRESS ((uint8_t)0) diff --git a/libraries/MySensors/core/MySigning.cpp b/libraries/MySensors/core/MySigning.cpp index 6e95b4a..7d297e2 100644 --- a/libraries/MySensors/core/MySigning.cpp +++ b/libraries/MySensors/core/MySigning.cpp @@ -20,6 +20,10 @@ #include "MySigning.h" #include "drivers/ATSHA204/sha256.h" +#define SIGNING_PRESENTATION_VERSION_1 1 +#define SIGNING_PRESENTATION_REQUIRE_SIGNATURES (1 << 0) +#define SIGNING_PRESENTATION_REQUIRE_WHITELISTING (1 << 1) + #if defined(MY_DEBUG_VERBOSE) #define SIGN_DEBUG(x,...) debug(x, ##__VA_ARGS__) #else @@ -30,8 +34,9 @@ #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 _doSign[32]; // Bitfield indicating which sensors require signed communication +uint8_t _doWhitelist[32]; // Bitfield indicating which sensors require serial salted signatures +MyMessage _msgSign; // Buffer for message to sign. uint8_t _signingNonceStatus; // Status when waiting for signing nonce in signerProcessInternal @@ -72,7 +77,7 @@ static bool skipSign(MyMessage &msg) { SIGN_DEBUG(PSTR("Skipping security for ACK on command %d type %d\n"), mGetCommand(msg), msg.type); return true; } else if (mGetCommand(msg) == C_INTERNAL && - (msg.type == I_NONCE_REQUEST || msg.type == I_NONCE_RESPONSE || msg.type == I_REQUEST_SIGNING || + (msg.type == I_NONCE_REQUEST || msg.type == I_NONCE_RESPONSE || msg.type == I_SIGNING_PRESENTATION || msg.type == I_ID_REQUEST || msg.type == I_ID_RESPONSE || msg.type == I_FIND_PARENT || msg.type == I_FIND_PARENT_RESPONSE || msg.type == I_HEARTBEAT || msg.type == I_HEARTBEAT_RESPONSE)) { @@ -89,10 +94,24 @@ static bool skipSign(MyMessage &msg) { } #endif // MY_SIGNING_FEATURE +// Helper to prepare a signing presentation message +static void prepareSigningPresentation(MyMessage &msg, uint8_t destination) { + // Only supports version 1 for now + build(msg, _nc.nodeId, destination, NODE_SENSOR_ID, C_INTERNAL, I_SIGNING_PRESENTATION, false).set(""); + mSetLength(msg, 2); + msg.data[0] = SIGNING_PRESENTATION_VERSION_1; + msg.data[1] = 0; +} + void signerInit(void) { #if defined(MY_SIGNING_FEATURE) // Read out the signing requirements from EEPROM - hwReadConfigBlock((void*)_doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, sizeof(_doSign)); + hwReadConfigBlock((void*)_doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, + sizeof(_doSign)); + + // Read out the whitelist requirements from EEPROM + hwReadConfigBlock((void*)_doWhitelist, (void*)EEPROM_WHITELIST_REQUIREMENT_TABLE_ADDRESS, + sizeof(_doWhitelist)); #if defined(MY_SIGNING_SOFT) // initialize pseudo-RNG @@ -102,21 +121,23 @@ void signerInit(void) { } void signerPresentation(MyMessage &msg) { -#ifdef MY_SIGNING_FEATURE + prepareSigningPresentation(msg, GATEWAY_ADDRESS); + #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 - SIGN_DEBUG(PSTR("Request for signing sent, waiting for GW response...\n")); - wait(2000); -#else - _sendRoute(build(msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, - C_INTERNAL, I_REQUEST_SIGNING, false).set(false)); + msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_SIGNATURES; + SIGN_DEBUG(PSTR("Signing required\n")); #endif -#else - // Ww 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)); +#if defined(MY_SIGNING_NODE_WHITELISTING) + msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_WHITELISTING; + SIGN_DEBUG(PSTR("Whitelisting required\n")); +#endif + + _sendRoute(msg); + +#if defined(MY_SIGNING_FEATURE) + // If we do support signing, wait for the gateway to tell us how it prefer us to transmit our messages + SIGN_DEBUG(PSTR("Waiting for GW to send signing preferences...\n")); + wait(2000); #endif } @@ -125,12 +146,12 @@ bool signerProcessInternal(MyMessage &msg) { #if !defined(MY_SIGNING_FEATURE) && defined(MY_GATEWAY_FEATURE) // If we act as gateway and do not have the signing feature and receive a signing request we still // need to do make sure the requester does not believe the gateway still require signatures - if (msg.type == I_REQUEST_SIGNING) { - _sendRoute(build(msg, _nc.nodeId, msg.sender, NODE_SENSOR_ID, - C_INTERNAL, I_REQUEST_SIGNING, false).set((uint8_t)false)); + if (msg.type == I_SIGNING_PRESENTATION) { + prepareSigningPresentation(msg, msg.sender); SIGN_DEBUG(PSTR("Informing node %d that we do not require signatures because we do not support it\n"), msg.sender); - return true; // No need to further process I_REQUEST_SIGNING in this case + _sendRoute(msg); + return true; // No need to further process I_SIGNING_PRESENTATION in this case } #elif defined(MY_SIGNING_FEATURE) if (msg.type == I_NONCE_REQUEST) { @@ -147,8 +168,14 @@ bool signerProcessInternal(MyMessage &msg) { SIGN_DEBUG(PSTR("Failed to generate nonce!\n")); } return true; // No need to further process I_NONCE_REQUEST - } else if (msg.type == I_REQUEST_SIGNING) { - if (msg.getBool()) { + } else if (msg.type == I_SIGNING_PRESENTATION) { + if (msg.data[0] != SIGNING_PRESENTATION_VERSION_1) { + SIGN_DEBUG(PSTR("Unsupported signing presentation version (%d)!\n"), msg.data[0]); + return true; // Just drop this presentation message + } + + // We only handle version 1 here... + if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_SIGNATURES) { // We received an indicator that the sender require us to sign all messages we send to it SIGN_DEBUG(PSTR("Mark node %d as one that require signed messages\n"), msg.sender); SET_SIGN(msg.sender); @@ -157,32 +184,52 @@ bool signerProcessInternal(MyMessage &msg) { SIGN_DEBUG(PSTR("Mark node %d as one that do not require signed messages\n"), msg.sender); CLEAR_SIGN(msg.sender); } - // Save updated table - hwWriteConfigBlock((void*)_doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, sizeof(_doSign)); + + if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_WHITELISTING) { + // We received an indicator that the sender require us to salt signatures with serial + SIGN_DEBUG(PSTR("Mark node %d as one that require whitelisting\n"), msg.sender); + SET_WHITELIST(msg.sender); + } else { + // We received an indicator that the sender does not require us to sign all messages we send to it + SIGN_DEBUG(PSTR("Mark node %d as one that do not require whitelisting\n"), msg.sender); + CLEAR_WHITELIST(msg.sender); + } + + // Save updated tables + hwWriteConfigBlock((void*)_doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, + sizeof(_doSign)); + hwWriteConfigBlock((void*)_doWhitelist, (void*)EEPROM_WHITELIST_REQUIREMENT_TABLE_ADDRESS, + sizeof(_doWhitelist)); // Inform sender about our preference if we are a gateway, but only require signing if the sender // required signing // We do not 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 defined(MY_GATEWAY_FEATURE) + prepareSigningPresentation(msg, msg.sender); +#if defined(MY_SIGNING_REQUEST_SIGNATURES) if (DO_SIGN(msg.sender)) { - _sendRoute(build(msg, _nc.nodeId, msg.sender, NODE_SENSOR_ID, - C_INTERNAL, I_REQUEST_SIGNING, false).set((uint8_t)true)); - SIGN_DEBUG(PSTR("Informing node %d that we require signatures\n"), msg.sender); + msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_SIGNATURES; } - else { - _sendRoute(build(msg, _nc.nodeId, msg.sender, NODE_SENSOR_ID, - C_INTERNAL, I_REQUEST_SIGNING, false).set((uint8_t)false)); +#endif +#if defined(MY_SIGNING_NODE_WHITELISTING) + if (DO_WHITELIST(msg.sender)) { + msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_WHITELISTING; + } +#endif + if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_SIGNATURES) { + SIGN_DEBUG(PSTR("Informing node %d that we require signatures\n"), msg.sender); + } else { SIGN_DEBUG(PSTR("Informing node %d that we do not require signatures\n"), msg.sender); } -#else // no MY_SIGNING_REQUEST_SIGNATURES - _sendRoute(build(msg, _nc.nodeId, msg.sender, NODE_SENSOR_ID, - C_INTERNAL, I_REQUEST_SIGNING, false).set((uint8_t)false)); - SIGN_DEBUG(PSTR("Informing node %d that we do not require signatures\n"), msg.sender); -#endif + if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_WHITELISTING) { + SIGN_DEBUG(PSTR("Informing node %d that we require whitelisting\n"), msg.sender); + } else { + SIGN_DEBUG(PSTR("Informing node %d that we do not require whitelisting\n"), msg.sender); + } + _sendRoute(msg); #endif // MY_GATEWAY_FEATURE - return true; // No need to further process I_REQUEST_SIGNING + return true; // No need to further process I_SIGNING_PRESENTATION } else if (msg.type == I_NONCE_RESPONSE) { // Proceed with signing if nonce has been received SIGN_DEBUG(PSTR("Nonce received from %d. Proceeding with signing...\n"), msg.sender); diff --git a/libraries/MySensors/core/MySigning.h b/libraries/MySensors/core/MySigning.h index 4f69c81..10de162 100644 --- a/libraries/MySensors/core/MySigning.h +++ b/libraries/MySensors/core/MySigning.h @@ -251,9 +251,9 @@ * This also applies to the gateway. However, the difference is that the gateway will only require signed messages from nodes it knows in turn * require signed messages.
* A node can also inform a different node that it expects to receive signed messages from it. This is done by transmitting an internal message - * of type @ref I_REQUEST_SIGNING and provide a boolean for payload, set to @c true.
+ * of type @ref I_SIGNING_PRESENTATION and provide flags as payload that inform the receiver of the signing preferences of the sender.
* All nodes and gateways in a network maintain a table where the signing preferences of all nodes are stored. This is also stored in EEPROM so - * if the gateway reboots, the nodes does not have to retransmit a signing request to the gateway for the gateway to realize that the node + * if the gateway reboots, the nodes does not have to retransmit a signing presentation to the gateway for the gateway to realize that the node * expect signed messages.
* Also, the nodes that do not require signed messages will also inform gateway of this, so if you reprogram a node to stop require signing, * the gateway will adhere to this as soon as the new node has presented itself to the gateway. @@ -294,7 +294,6 @@ * The whitelist is stored on the node that require signatures. When a received message is verified, the serial of the sender is looked up in a * list stored on the receiving node, and the corresponding serial stored in the list for that sender is then included in the signature verification * process. The list is stored as the value of the flag that enables whitelisting, @ref MY_SIGNING_NODE_WHITELISTING.
- * For whitelisting to work, the sending node also needs to have whitelisting enabled.
* * Whitelisting is achieved by 'salting' the signature with some node-unique information known to the receiver. In the case of ATSHA204A this is the * unique serial number programmed into the circuit. This unique number is never transmitted over the air in clear text, so Eve will not be able to @@ -303,8 +302,8 @@ * the originating NodeId of the signed message and do the corresponding calculation with the serial it has stored in it's whitelist if it finds a * matching entry in it's whitelist. * - * Whitelisting is an optional alternative because it adds some code which might not be desirable for every user. So if you want the ability to - * provide and use whitelists, as well as transmitting to a node with a whitelist, you need to enable @ref MY_SIGNING_NODE_WHITELISTING.
+ * Whitelisting is an optional alternative because it adds some code and configuration options which might not be desirable for every user. So if + * you want the ability to use whitelists, you need to enable @ref MY_SIGNING_NODE_WHITELISTING.
* The whitelist is provided as value of the flag that enable it as follows (example is a node that require signing as well): * @code{.cpp} * #define MY_SIGNING_ATSHA204 @@ -314,10 +313,10 @@ * ... * @endcode * In this example, there are two nodes in the whitelist; the gateway, and a separate node that communicates directly with this node (with signed - * messages). + * messages). You do not need to do anything special for the sending nodes, apart from making sure they support signing. * * The "soft" backend of course also support whitelisting. However, since it does not contain a unique identifier, you have to provide an additional - * setting (@ref MY_SIGNING_SOFT_SERIAL) when you enable whitelisting as illustrated in this example: + * setting (@ref MY_SIGNING_SOFT_SERIAL) for all nodes that communicate to a node which has whitelisting enabled. Example: * @code{.cpp} * #define MY_SIGNING_SOFT * #define MY_SIGNING_SOFT_SERIAL 0x12,0x34,0x56,0x78,0x90,0x12,0x34,0x56,0x78 @@ -329,16 +328,16 @@ * ... * @endcode * - * For a node that should transmit whitelisted messages but not receive whitelisted messages, you can set the whitelist flag as follows: + * For a node that should transmit whitelisted messages but not receive whitelisted messages, you do not need any special configurations except to define + * a unique serial if using the software backend: * @code{.cpp} - * #define MY_SIGNING_NODE_WHITELISTING {} + * #define MY_SIGNING_SOFT + * #define MY_SIGNING_SOFT_SERIAL 0x12,0x34,0x56,0x78,0x90,0x12,0x34,0x56,0x78 + * #define MY_SIGNING_SOFT_RANDOMSEED_PIN 7 + * #define MY_SIGNING_SOFT_HMAC_KEY 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xa0,0xb0,0xc0,0xd0,0xe0,0xf0,0x11,0x22 * @endcode - * Remember that for the software backend, you still need to set @ref MY_SIGNING_SOFT_SERIAL (a default is set in MyConfig.h if you do not provide one - * in your sketch. - * - * It is important to emphasize that you do not have to provide a whitelist that has entries for all nodes that transmit signed messages to the node - * in question. You only need to have entries for the nodes that in turn have enabled @ref MY_SIGNING_NODE_WHITELISTING. Nodes that does not have - * this option enabled can still transmit "regular" signed messages as long as they do not match a NodeId in the receivers whitelist. + * Remember that you always need to select a signing backend for all nodes that communicate to a node that require whitelisting. + * Also, note that a node that use whitelisting will not accept messages from nodes that are not present in it's whitelist. * * @section MySigningtechnical The technical stuff * @@ -363,7 +362,7 @@ * Exactly how this is done can be reviewd in the source for the ATSHA204SOFT backend and the ATSHA204A * datasheet. * In the MySensors protocol, the following internal messagetypes handles signature requirements and nonce requests:
- * @ref I_REQUEST_SIGNING
+ * @ref I_SIGNING_PRESENTATION
* @ref I_NONCE_REQUEST
* @ref I_NONCE_RESPONSE
* @@ -409,14 +408,13 @@ * Nor can it be changed in order to do it in the future. You can also use whitelisting to revoke your lost node.
* This is an unlikely use case because there really is no reason to sign sensor values. If you for some reason want to obfuscate sensor data, * encryption is a better alternative.
- * Configuration example for a motion sensor with whitelisting (it has to have the gateway whitelisted since the gateway will send signed messages to the node):
+ * Configuration example for a motion sensor:
* @code{.cpp} * #define MY_SIGNING_SOFT * #define MY_SIGNING_SOFT_SERIAL 0x12,0x34,0x56,0x78,0x90,0x12,0x34,0x56,0x78 * #define MY_SIGNING_SOFT_RANDOMSEED_PIN 7 * #define MY_SIGNING_SOFT_HMAC_KEY 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xa0,0xb0,0xc0,0xd0,0xe0,0xf0,0x11,0x22 * #define MY_SIGNING_REQUEST_SIGNATURES - * #define MY_SIGNING_NODE_WHITELISTING {{.nodeId = GATEWAY_ADDRESS,.serial = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88}}} * #include * ... * @endcode @@ -441,10 +439,10 @@ * Configuration example for the keyfob (keyfob will only transmit to another node and not receive anything):
* @code{.cpp} * #define MY_SIGNING_ATSHA204 - * #define MY_SIGNING_NODE_WHITELISTING {} * #include * ... * @endcode + * * Configuration example for the door controller node (should require signing from anyone who wants to control it):
* @code{.cpp} * #define MY_SIGNING_SOFT @@ -487,6 +485,14 @@ typedef struct { /** @brief Helper macro to determine the number of elements in a array */ #define NUM_OF(x) (sizeof(x)/sizeof(x[0])) +/** @brief Helper macro to determine if node require serial salted signatures */ +#define DO_WHITELIST(node) (~_doWhitelist[node>>3]&(1<>3]&=~(1<>3]|=(1< Date: Sun, 3 Jan 2016 19:40:02 +0100 Subject: [PATCH 08/10] MY_DEBUG_VERBOSE_SIGNING flag implemented This enables more verbose debug information for signing operations. Fixes #319 --- libraries/MySensors/MyConfig.h | 8 +++++++- libraries/MySensors/core/MySigning.cpp | 2 +- libraries/MySensors/core/MySigningAtsha204.cpp | 4 ++-- libraries/MySensors/core/MySigningAtsha204Soft.cpp | 4 ++-- .../MySensors/examples/SecureActuator/SecureActuator.ino | 1 + libraries/MySensors/keywords.txt | 2 ++ 6 files changed, 15 insertions(+), 6 deletions(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index ac9d1df..19648a3 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -35,10 +35,16 @@ // final sketch but is helpful to see what is actually is happening during development //#define MY_DEBUG -// Enable MY_DEBUG_VERBOSE flag for verbose debug prints. Requires DEBUG to be enabled. +// Enable MY_DEBUG_VERBOSE flag for verbose debug prints related to RF24 radio. +// Requires DEBUG to be enabled. // This will add even more to the size of the final sketch! //#define MY_DEBUG_VERBOSE +// Enable MY_DEBUG_VERBOSE_SIGNING flag for verbose debug prints related to signing. +// Requires DEBUG to be enabled. +// This will add even more to the size of the final sketch! +//#define MY_DEBUG_VERBOSE_SIGNING + // Enable this in sketch if you want to use TX(1), RX(0) as normal I/O pin //#define MY_DISABLED_SERIAL diff --git a/libraries/MySensors/core/MySigning.cpp b/libraries/MySensors/core/MySigning.cpp index 7d297e2..2d0225c 100644 --- a/libraries/MySensors/core/MySigning.cpp +++ b/libraries/MySensors/core/MySigning.cpp @@ -24,7 +24,7 @@ #define SIGNING_PRESENTATION_REQUIRE_SIGNATURES (1 << 0) #define SIGNING_PRESENTATION_REQUIRE_WHITELISTING (1 << 1) -#if defined(MY_DEBUG_VERBOSE) +#if defined(MY_DEBUG_VERBOSE_SIGNING) #define SIGN_DEBUG(x,...) debug(x, ##__VA_ARGS__) #else #define SIGN_DEBUG(x,...) diff --git a/libraries/MySensors/core/MySigningAtsha204.cpp b/libraries/MySensors/core/MySigningAtsha204.cpp index bd47d0d..b5ac3ca 100644 --- a/libraries/MySensors/core/MySigningAtsha204.cpp +++ b/libraries/MySensors/core/MySigningAtsha204.cpp @@ -29,7 +29,7 @@ #define SIGNING_IDENTIFIER (1) -// Define MY_DEBUG_VERBOSE in your sketch to enable signing backend debugprints +// Define MY_DEBUG_VERBOSE_SIGNING in your sketch to enable signing backend debugprints ATSHA204Class atsha204(MY_SIGNING_ATSHA204_PIN); unsigned long _signing_timestamp; @@ -48,7 +48,7 @@ static void signerCalculateSignature(MyMessage &msg); static uint8_t* signerSha256(const uint8_t* data, size_t sz); -#ifdef MY_DEBUG_VERBOSE +#ifdef MY_DEBUG_VERBOSE_SIGNING static char i2h(uint8_t i) { uint8_t k = i & 0x0F; diff --git a/libraries/MySensors/core/MySigningAtsha204Soft.cpp b/libraries/MySensors/core/MySigningAtsha204Soft.cpp index c0a2234..2940d09 100644 --- a/libraries/MySensors/core/MySigningAtsha204Soft.cpp +++ b/libraries/MySensors/core/MySigningAtsha204Soft.cpp @@ -33,7 +33,7 @@ #define SIGNING_IDENTIFIER (1) -// Define MY_DEBUG_VERBOSE in your sketch to enable signing backend debugprints +// Define MY_DEBUG_VERBOSE_SIGNING in your sketch to enable signing backend debugprints Sha256Class _signing_sha256; unsigned long _signing_timestamp; @@ -51,7 +51,7 @@ const uint8_t _signing_node_serial_info[SHA204_SERIAL_SZ] = {MY_SIGNING_SOFT_SER static void signerCalculateSignature(MyMessage &msg); -#ifdef MY_DEBUG_VERBOSE +#ifdef MY_DEBUG_VERBOSE_SIGNING static char i2h(uint8_t i) { uint8_t k = i & 0x0F; diff --git a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino index aedcd71..3e6c6bb 100644 --- a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino +++ b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino @@ -43,6 +43,7 @@ */ #define MY_DEBUG //!< Enable debug prints to serial monitor +#define MY_DEBUG_VERBOSE_SIGNING //!< Enable signing related debug prints to serial monitor // Enable and select radio type attached #define MY_RADIO_NRF24 //!< NRF24L01 radio driver diff --git a/libraries/MySensors/keywords.txt b/libraries/MySensors/keywords.txt index 3ee0f8a..257dcbf 100644 --- a/libraries/MySensors/keywords.txt +++ b/libraries/MySensors/keywords.txt @@ -32,6 +32,8 @@ smartSleep KEYWORD2 AUTO LITERAL1 MY_DEBUG LITERAL1 MY_CORE_ONLY LITERAL1 +MY_DEBUG_VERBOSE LITERAL1 +MY_DEBUG_VERBOSE_SIGNING LITERAL1 MY_REPEATER_FEATURE LITERAL1 MY_RADIO_NRF24 LITERAL1 MY_RADIO_RFM69 LITERAL1 From 3bf9184670583f695f4062d402f5a088079526da Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sun, 3 Jan 2016 20:51:40 +0100 Subject: [PATCH 09/10] Removed signing identifier from nonces It serves no practical use to have signing identifier in nonces as nonces are architecture independent. Fixes #318 --- libraries/MySensors/core/MySigning.cpp | 13 ++++++------- libraries/MySensors/core/MySigningAtsha204.cpp | 10 +--------- libraries/MySensors/core/MySigningAtsha204Soft.cpp | 10 +--------- 3 files changed, 8 insertions(+), 25 deletions(-) diff --git a/libraries/MySensors/core/MySigning.cpp b/libraries/MySensors/core/MySigning.cpp index 2d0225c..1202474 100644 --- a/libraries/MySensors/core/MySigning.cpp +++ b/libraries/MySensors/core/MySigning.cpp @@ -59,14 +59,14 @@ enum { SIGN_WAITING_FOR_NONCE = 0, SIGN_OK = 1 }; #if defined(MY_SIGNING_SOFT) extern bool signerAtsha204SoftCheckTimer(void); extern bool signerAtsha204SoftGetNonce(MyMessage &msg); -extern bool signerAtsha204SoftPutNonce(MyMessage &msg); +extern void signerAtsha204SoftPutNonce(MyMessage &msg); extern bool signerAtsha204SoftVerifyMsg(MyMessage &msg); extern bool signerAtsha204SoftSignMsg(MyMessage &msg); #endif #if defined(MY_SIGNING_ATSHA204) extern bool signerAtsha204CheckTimer(void); extern bool signerAtsha204GetNonce(MyMessage &msg); -extern bool signerAtsha204PutNonce(MyMessage &msg); +extern void signerAtsha204PutNonce(MyMessage &msg); extern bool signerAtsha204VerifyMsg(MyMessage &msg); extern bool signerAtsha204SignMsg(MyMessage &msg); #endif @@ -240,17 +240,16 @@ bool signerProcessInternal(MyMessage &msg) { return true; // No need to further process I_NONCE_RESPONSE } #if defined(MY_SIGNING_SOFT) - if (!signerAtsha204SoftPutNonce(msg)) { + signerAtsha204SoftPutNonce(msg); #endif #if defined(MY_SIGNING_ATSHA204) - if (!signerAtsha204PutNonce(msg)) { + signerAtsha204PutNonce(msg); #endif - SIGN_DEBUG(PSTR("Failed to store nonce to signing backend!\n")); #if defined(MY_SIGNING_SOFT) - } else if (!signerAtsha204SoftSignMsg(_msgSign)) { + if (!signerAtsha204SoftSignMsg(_msgSign)) { #endif #if defined(MY_SIGNING_ATSHA204) - } else if (!signerAtsha204SignMsg(_msgSign)) { + if (!signerAtsha204SignMsg(_msgSign)) { #endif SIGN_DEBUG(PSTR("Failed to sign message!\n")); } else { diff --git a/libraries/MySensors/core/MySigningAtsha204.cpp b/libraries/MySensors/core/MySigningAtsha204.cpp index b5ac3ca..ce78678 100644 --- a/libraries/MySensors/core/MySigningAtsha204.cpp +++ b/libraries/MySensors/core/MySigningAtsha204.cpp @@ -117,9 +117,6 @@ bool signerAtsha204GetNonce(MyMessage &msg) { // We set the part of the 32-byte nonce that does not fit into a message to 0xAA memset(&_signing_current_nonce[MAX_PAYLOAD], 0xAA, sizeof(_signing_current_nonce)-MAX_PAYLOAD); - // Replace the first byte in the nonce with our signing identifier - _signing_current_nonce[0] = SIGNING_IDENTIFIER; - // Transfer the first part of the nonce to the message msg.set(_signing_current_nonce, MAX_PAYLOAD); _signing_verification_ongoing = true; @@ -131,17 +128,12 @@ bool signerAtsha204GetNonce(MyMessage &msg) { return true; } -bool signerAtsha204PutNonce(MyMessage &msg) { +void 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); - return false; - } memcpy(_signing_current_nonce, (uint8_t*)msg.getCustom(), MAX_PAYLOAD); // We set the part of the 32-byte nonce that does not fit into a message to 0xAA memset(&_signing_current_nonce[MAX_PAYLOAD], 0xAA, sizeof(_signing_current_nonce)-MAX_PAYLOAD); - return true; } bool signerAtsha204SignMsg(MyMessage &msg) { diff --git a/libraries/MySensors/core/MySigningAtsha204Soft.cpp b/libraries/MySensors/core/MySigningAtsha204Soft.cpp index 2940d09..2b89fac 100644 --- a/libraries/MySensors/core/MySigningAtsha204Soft.cpp +++ b/libraries/MySensors/core/MySigningAtsha204Soft.cpp @@ -117,9 +117,6 @@ bool signerAtsha204SoftGetNonce(MyMessage &msg) { // We set the part of the 32-byte nonce that does not fit into a message to 0xAA memset(&_signing_current_nonce[MAX_PAYLOAD], 0xAA, sizeof(_signing_current_nonce)-MAX_PAYLOAD); - // Replace the first byte in the nonce with our signing identifier - _signing_current_nonce[0] = SIGNING_IDENTIFIER; - // Transfer the first part of the nonce to the message msg.set(_signing_current_nonce, MAX_PAYLOAD); _signing_verification_ongoing = true; @@ -131,17 +128,12 @@ bool signerAtsha204SoftGetNonce(MyMessage &msg) { return true; } -bool signerAtsha204SoftPutNonce(MyMessage &msg) { +void 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); - return false; - } memcpy(_signing_current_nonce, (uint8_t*)msg.getCustom(), MAX_PAYLOAD); // We set the part of the 32-byte nonce that does not fit into a message to 0xAA memset(&_signing_current_nonce[MAX_PAYLOAD], 0xAA, sizeof(_signing_current_nonce)-MAX_PAYLOAD); - return true; } bool signerAtsha204SoftSignMsg(MyMessage &msg) { From c52d2cd64345bc03b59977bc66c8f2ce97c7b06e Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Fri, 8 Jan 2016 14:28:31 +0100 Subject: [PATCH 10/10] All software security related data moved to EEPROM The Sha204Personalizer has been converted to a SecurityPersonalizer. It takes care of generation and storage of keys and data to both ATSHA204A and nonvolatile storage (EEPROM). Library has been updated to read any software security related data from the corresponding EEPROM locations. The effect this has is that any node using any security feature has to execute the personalizer at least once to store appropriate values. The benefit of this is that the software no longer contain sensitive data such as HMAC or AES keys. Whitelists still are stored in software as they are variable in size. --- libraries/MySensors/MyConfig.h | 31 +- libraries/MySensors/core/MyEepromAddresses.h | 43 ++ libraries/MySensors/core/MyHwESP8266.cpp | 2 +- .../MySensors/core/MyPrivateConfig.h.sample | 10 - libraries/MySensors/core/MySensorCore.h | 19 +- libraries/MySensors/core/MySigning.cpp | 8 +- libraries/MySensors/core/MySigning.h | 62 +-- .../MySensors/core/MySigningAtsha204.cpp | 3 + .../MySensors/core/MySigningAtsha204Soft.cpp | 12 +- libraries/MySensors/core/MyTransportNRF24.cpp | 4 +- libraries/MySensors/core/MyTransportRFM69.cpp | 5 +- libraries/MySensors/drivers/AES/AES.h | 10 +- .../SecureActuator/SecureActuator.ino | 6 - .../SecurityPersonalizer.ino} | 377 ++++++++++++++++-- libraries/MySensors/keywords.txt | 5 +- 15 files changed, 454 insertions(+), 143 deletions(-) create mode 100644 libraries/MySensors/core/MyEepromAddresses.h rename libraries/MySensors/examples/{Sha204Personalizer/Sha204Personalizer.ino => SecurityPersonalizer/SecurityPersonalizer.ino} (73%) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 19648a3..bbbabdb 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -289,25 +289,6 @@ #define MY_SIGNING_SOFT_RANDOMSEED_PIN 7 #endif -/** - * @def MY_SIGNING_SOFT_SERIAL - * @brief Serial number for SW signing enabled node - * - * Set the soft_serial value to an arbitrary value for proper security. - * It should be random and unique for each node. - */ -#ifndef MY_SIGNING_SOFT_SERIAL -#define MY_SIGNING_SOFT_SERIAL 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09 -#endif - -/** - * @def MY_SIGNING_SOFT_HMAC_KEY - * @brief Key to use for HMAC calculation in MySigningAtsha204Soft (32 bytes) - */ -#ifndef MY_SIGNING_SOFT_HMAC_KEY -#define MY_SIGNING_SOFT_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -#endif - /********************************** * RS485 Driver Defaults ***********************************/ @@ -324,14 +305,9 @@ * NRF24L01 Driver Defaults ***********************************/ -// Enables RF24 encryption (all nodes and gateway must have this enabled) +// Enables RF24 encryption (all nodes and gateway must have this enabled, and all must be personalized with the same AES key) //#define MY_RF24_ENABLE_ENCRYPTION -// Default encryption key. Override in sketch if needed. -#ifndef MY_RF24_ENCRYPTKEY -#define MY_RF24_ENCRYPTKEY 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x10,0x11,0x12,0x13,0x14,0x15,0x16 -#endif - // Default pin settings. Override in sketch if needed. #ifndef MY_RF24_CE_PIN #if defined(ARDUINO_ARCH_ESP8266) @@ -418,11 +394,8 @@ #endif #endif -// Enable this for encryption of packets +// Enables RFM69 encryption (all nodes and gateway must have this enabled, and all must be personalized with the same AES key) //#define MY_RFM69_ENABLE_ENCRYPTION -#ifndef MY_RFM69_ENCRYPTKEY -#define MY_RFM69_ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes! -#endif /************************************** * Ethernet Gateway Transport Defaults diff --git a/libraries/MySensors/core/MyEepromAddresses.h b/libraries/MySensors/core/MyEepromAddresses.h new file mode 100644 index 0000000..510126f --- /dev/null +++ b/libraries/MySensors/core/MyEepromAddresses.h @@ -0,0 +1,43 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#ifndef MyEepromAddresses_h +#define MyEepromAddresses_h +// EEPROM start address for mysensors library data +#define EEPROM_START 0 +// EEPROM location of node id +#define EEPROM_NODE_ID_ADDRESS EEPROM_START +// EEPROM location of parent id +#define EEPROM_PARENT_NODE_ID_ADDRESS (EEPROM_START+1) +// EEPROM location of distance to gateway +#define EEPROM_DISTANCE_ADDRESS (EEPROM_PARENT_NODE_ID_ADDRESS+1) +#define EEPROM_ROUTES_ADDRESS (EEPROM_DISTANCE_ADDRESS+1) // Where to start storing routing information in EEPROM. Will allocate 256 bytes. +#define EEPROM_CONTROLLER_CONFIG_ADDRESS (EEPROM_ROUTES_ADDRESS+256) // Location of controller sent configuration (we allow one payload of config data from controller) +#define EEPROM_FIRMWARE_TYPE_ADDRESS (EEPROM_CONTROLLER_CONFIG_ADDRESS+24) +#define EEPROM_FIRMWARE_VERSION_ADDRESS (EEPROM_FIRMWARE_TYPE_ADDRESS+2) +#define EEPROM_FIRMWARE_BLOCKS_ADDRESS (EEPROM_FIRMWARE_VERSION_ADDRESS+2) +#define EEPROM_FIRMWARE_CRC_ADDRESS (EEPROM_FIRMWARE_BLOCKS_ADDRESS+2) +#define EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS (EEPROM_FIRMWARE_CRC_ADDRESS+2) +#define EEPROM_WHITELIST_REQUIREMENT_TABLE_ADDRESS (EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS+32) +#define EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS (EEPROM_WHITELIST_REQUIREMENT_TABLE_ADDRESS+32) // This is set with SecurityPersonalizer.ino +#define EEPROM_SIGNING_SOFT_SERIAL_ADDRESS (EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS+32) // This is set with SecurityPersonalizer.ino +#define EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS (EEPROM_SIGNING_SOFT_SERIAL_ADDRESS+9) // This is set with SecurityPersonalizer.ino +#define EEPROM_LOCAL_CONFIG_ADDRESS (EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS+16) // First free address for sketch static configuration + +#endif diff --git a/libraries/MySensors/core/MyHwESP8266.cpp b/libraries/MySensors/core/MyHwESP8266.cpp index 946210a..cec567f 100644 --- a/libraries/MySensors/core/MyHwESP8266.cpp +++ b/libraries/MySensors/core/MyHwESP8266.cpp @@ -18,7 +18,7 @@ */ #include "MyHwESP8266.h" - +#include /* int8_t pinIntTrigger = 0; diff --git a/libraries/MySensors/core/MyPrivateConfig.h.sample b/libraries/MySensors/core/MyPrivateConfig.h.sample index 3ac1175..099fd36 100644 --- a/libraries/MySensors/core/MyPrivateConfig.h.sample +++ b/libraries/MySensors/core/MyPrivateConfig.h.sample @@ -40,12 +40,6 @@ // Pin used for random generation in soft signing (do not connect anything to this when enabled) #define MY_SIGNING_SOFT_RANDOMSEED_PIN 7 // A7 - -// Set the soft_serial value to an arbitrary value for proper security -#define MY_SIGNING_SOFT_SERIAL 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09 - -// Key to use for HMAC calculation in MySigningAtsha204Soft (32 bytes) -#define MY_SIGNING_SOFT_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 - // Enable node whitelisting //#define MY_SIGNING_NODE_WHITELISTING {{.nodeId = GATEWAY_ADDRESS,.serial = {0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01}}} @@ -55,9 +49,6 @@ // Enables RF24 encryption (all nodes and gateway must have this enabled) //#define MY_RF24_ENABLE_ENCRYPTION -// Default encryption key -#define MY_RF24_ENCRYPTKEY 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x10,0x11,0x12,0x13,0x14,0x15,0x16 - /********************************** * RFM69 Driver Defaults ***********************************/ @@ -66,6 +57,5 @@ // Enable this for encryption of packets //#define MY_RFM69_ENABLE_ENCRYPTION -#define MY_RFM69_ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes! #endif diff --git a/libraries/MySensors/core/MySensorCore.h b/libraries/MySensors/core/MySensorCore.h index 6400373..1991673 100644 --- a/libraries/MySensors/core/MySensorCore.h +++ b/libraries/MySensors/core/MySensorCore.h @@ -23,6 +23,7 @@ #include "Version.h" // Auto generated by bot #include "MyConfig.h" +#include "MyEepromAddresses.h" #include "MyMessage.h" #ifdef MY_OTA_FIRMWARE_FEATURE #include "drivers/SPIFlash/SPIFlash.h" @@ -37,24 +38,6 @@ #define debug(x,...) #endif -// EEPROM start address for mysensors library data -#define EEPROM_START 0 -// EEPROM location of node id -#define EEPROM_NODE_ID_ADDRESS EEPROM_START -// EEPROM location of parent id -#define EEPROM_PARENT_NODE_ID_ADDRESS (EEPROM_START+1) -// EEPROM location of distance to gateway -#define EEPROM_DISTANCE_ADDRESS (EEPROM_PARENT_NODE_ID_ADDRESS+1) -#define EEPROM_ROUTES_ADDRESS (EEPROM_DISTANCE_ADDRESS+1) // Where to start storing routing information in EEPROM. Will allocate 256 bytes. -#define EEPROM_CONTROLLER_CONFIG_ADDRESS (EEPROM_ROUTES_ADDRESS+256) // Location of controller sent configuration (we allow one payload of config data from controller) -#define EEPROM_FIRMWARE_TYPE_ADDRESS (EEPROM_CONTROLLER_CONFIG_ADDRESS+24) -#define EEPROM_FIRMWARE_VERSION_ADDRESS (EEPROM_FIRMWARE_TYPE_ADDRESS+2) -#define EEPROM_FIRMWARE_BLOCKS_ADDRESS (EEPROM_FIRMWARE_VERSION_ADDRESS+2) -#define EEPROM_FIRMWARE_CRC_ADDRESS (EEPROM_FIRMWARE_BLOCKS_ADDRESS+2) -#define EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS (EEPROM_FIRMWARE_CRC_ADDRESS+2) -#define EEPROM_WHITELIST_REQUIREMENT_TABLE_ADDRESS (EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS+32) -#define EEPROM_LOCAL_CONFIG_ADDRESS (EEPROM_WHITELIST_REQUIREMENT_TABLE_ADDRESS+32) // First free address for sketch static configuration - // This is the nodeId for sensor net gateway receiver sketch (where all sensors should send their data). #define GATEWAY_ADDRESS ((uint8_t)0) // Node child is always created/presented when a node is started diff --git a/libraries/MySensors/core/MySigning.cpp b/libraries/MySensors/core/MySigning.cpp index 1202474..689b374 100644 --- a/libraries/MySensors/core/MySigning.cpp +++ b/libraries/MySensors/core/MySigning.cpp @@ -57,6 +57,7 @@ enum { SIGN_WAITING_FOR_NONCE = 0, SIGN_OK = 1 }; * This function is typically called as action when receiving a I_NONCE_REQUEST message. */ #if defined(MY_SIGNING_SOFT) +extern void signerAtsha204SoftInit(void); extern bool signerAtsha204SoftCheckTimer(void); extern bool signerAtsha204SoftGetNonce(MyMessage &msg); extern void signerAtsha204SoftPutNonce(MyMessage &msg); @@ -64,6 +65,7 @@ extern bool signerAtsha204SoftVerifyMsg(MyMessage &msg); extern bool signerAtsha204SoftSignMsg(MyMessage &msg); #endif #if defined(MY_SIGNING_ATSHA204) +extern void signerAtsha204Init(void); extern bool signerAtsha204CheckTimer(void); extern bool signerAtsha204GetNonce(MyMessage &msg); extern void signerAtsha204PutNonce(MyMessage &msg); @@ -114,8 +116,10 @@ void signerInit(void) { sizeof(_doWhitelist)); #if defined(MY_SIGNING_SOFT) - // initialize pseudo-RNG - randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN)); + signerAtsha204SoftInit(); +#endif +#if defined(MY_SIGNING_ATSHA204) + signerAtsha204Init(); #endif #endif } diff --git a/libraries/MySensors/core/MySigning.h b/libraries/MySensors/core/MySigning.h index 10de162..68d76a8 100644 --- a/libraries/MySensors/core/MySigning.h +++ b/libraries/MySensors/core/MySigning.h @@ -178,14 +178,10 @@ * signatures. The setting is defined using @ref MY_SIGNING_SOFT_RANDOMSEED_PIN and the default is to use pin A7. The same configuration * possibilities exist as with the other configuration options. * - * Thirdly, if you use the software backend, you need to create/set a HMAC key to use. This key is 32 bytes wide and should - * be an arbitrarily chosen value. A string is OK, but as this key never needs to be “parsed” a completely random number is recommended. The - * key is stored in software and can be set "globally" in @ref MyConfig.h or locally in your sketch. The define is @ref MY_SIGNING_SOFT_HMAC_KEY. + * Thirdly, if you use the software backend, you need to personalize the node (see @ref perzonalization). * @code{.cpp} * #define MY_SIGNING_SOFT - * #define MY_SIGNING_SOFT_SERIAL 0x12,0x34,0x56,0x78,0x90,0x12,0x34,0x56,0x78 * #define MY_SIGNING_SOFT_RANDOMSEED_PIN 7 - * #define MY_SIGNING_SOFT_HMAC_KEY 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xa0,0xb0,0xc0,0xd0,0xe0,0xf0,0x11,0x22 * #define MY_SIGNING_REQUEST_SIGNATURES * #include * ... @@ -195,7 +191,8 @@ * * @anchor perzonalization If you use the “real” ATSHA204A, before any signing operations can be done, the device needs to be personalized. * This can be a daunting process as it involves irreversibly writing configurations to the device, which cannot be undone. I have however tried - * to simplify the process as much as possibly by creating a helper-sketch specifically for this purpose in @ref Sha204Personalizer.ino + * to simplify the process as much as possibly by creating a helper-sketch specifically for this purpose in @ref SecurityPersonalizer.ino + * Note that you also need to do personalization for software signing, but then the values are stored in EEPROM (described below). * * The process of personalizing the ATSHA204A involves * - Writing and locking chip configuration @@ -211,15 +208,15 @@ * if this is desired.
* Now it is possible to execute the sketch to lock the configuration and enable the RNG.
* Next step is to decide if a new key should be generated or an existing key should be stored to the device. This is determined using - * @ref USER_KEY_DATA, which, if defined, will use the data in the variable user_key_data.
- * If @ref USER_KEY_DATA is disabled, the RNG will be used to generate a key. This key obviously need to be made available to you so you can use + * @ref USER_KEY, which, if defined, will use the data in the variable user_key_data.
+ * If @ref USER_KEY is disabled, the RNG will be used to generate a key. This key obviously need to be made available to you so you can use * it in other devices in the network, and this key is therefore also printed on the serial console when it has been generated.
* The key (generated or provided) will be written to the device unless @ref SKIP_KEY_STORAGE is set. As long as the data zone is kept unlocked * the key can be replaced at any time. However, Atmel suggests the data region to be locked for maximum security. On the other hand, they also * claim that the key is not readable from the device even if the data zone remains unlocked so the need for locking the data region is optional * for MySensors usage.
* For devices that does not have serial debug possibilities, it is possible to set @ref SKIP_UART_CONFIRMATION, but it is required to set - * @ref USER_KEY_DATA if this option is enabled since a generated and potentially unknown key could be written to the device and thus rendering + * @ref USER_KEY if this option is enabled since a generated and potentially unknown key could be written to the device and thus rendering * it useless (if the data zone is also locked).
* For devices with serial debug possibilities it is recommended to not use @ref SKIP_UART_CONFIRMATION as the sketch without that setting will * ask user to send a ‘space’ character on the serial terminal before any locking operations are executed as an additional confirmation that @@ -232,7 +229,7 @@ * -# Disable @ref LOCK_DATA * -# Enable @ref SKIP_KEY_STORAGE * -# Disable @ref SKIP_UART_CONFIRMATION - * -# Disable @ref USER_KEY_DATA + * -# Disable @ref USER_KEY * - Execute the sketch on the “master” device to obtain a randomized key. Save this key to a secure location and keep it confidential so that\n you can retrieve it if you need to personalize more devices later on. * - Now reconfigure the sketch with these settings: @@ -241,10 +238,29 @@ * according to Atmel, but they also claim that key is not readable even if data region remains unlocked from the slot we are using) * -# Disable @ref SKIP_KEY_STORAGE * -# Enable @ref SKIP_UART_CONFIRMATION - * -# Enable @ref USER_KEY_DATA + * -# Enable @ref USER_KEY * - Put the saved key in the user_key_data variable. * - Now execute the sketch on all devices you want to personalize with this secret key. * + * For software signing the personalization procedure looks slightly different.
+ * - If you do not have the ATSHA204A device and need to generate random keys: + * -# Enable @ref USE_SOFT_SIGNING + * - If you do have the ATSHA204A and want to use it to generate random keys for soft signing: + * -# Disable @ref USE_SOFT_SIGNING + * - If you want to review existing EEPROM configuration to determine if anything needs to be updated: + * -# Make sure to disable any ATSHA204A update features if you use it (enable @ref SKIP_KEY_STORAGE, disable @ref LOCK_CONFIGURATION and @ref LOCK_DATA) + * -# Disable @ref STORE_SOFT_KEY + * -# Disable @ref STORE_SOFT_SERIAL + * -# Disable @ref STORE_AES_KEY + * - Execute the sketch and the EEPROM configuration will be printed on the serial console. + * - Decide what you want to update and enable the corresponding flags (@ref STORE_SOFT_KEY, @ref STORE_SOFT_SERIAL, @ref STORE_AES_KEY). + * - If you have existing keys and want to use them instead of having the values randomized: + * - Enable the corresponding flag (@ref USER_SOFT_KEY, @ref USER_SOFT_SERIAL, @ref USER_AES_KEY) and also set the appropriate values + * (@ref user_soft_key_data, @ref user_soft_serial, @ref user_aes_key) + * + * The personalizer also takes care of generation and storage of the AES key used for RF traffic encryption. + * See the software signing personalization flow for how to manage it. + * * That’s it. Personalization is done and the device is ready to execute signing operations which are valid only on your personal network. * * If a node does require signing, any unsigned message sent to the node will be rejected.
@@ -288,9 +304,8 @@ * remove it from the nodes whitelist, and it will no longer be able to communicate signed messages to the door node. * * In case you want to be able to "whitelist" trusted nodes (in order to be able to revoke them in case they are lost) you also need to take note - * of the serial number of the ATSHA device. This is unique for each device. The serial number is printed in a copy+paste friendly format by the - * personalizer for this purpose. For the software backend, it is defined by @ref MY_SIGNING_SOFT_SERIAL. You should keep this value unique for each - * node in the network.
+ * of the serial number of the ATSHA device or the software value stored in EEPROM. This is unique for each device. The serial number is printed + * in a copy+paste friendly format by the personalizer for this purpose.
* The whitelist is stored on the node that require signatures. When a received message is verified, the serial of the sender is looked up in a * list stored on the receiving node, and the corresponding serial stored in the list for that sender is then included in the signature verification * process. The list is stored as the value of the flag that enables whitelisting, @ref MY_SIGNING_NODE_WHITELISTING.
@@ -315,29 +330,24 @@ * In this example, there are two nodes in the whitelist; the gateway, and a separate node that communicates directly with this node (with signed * messages). You do not need to do anything special for the sending nodes, apart from making sure they support signing. * - * The "soft" backend of course also support whitelisting. However, since it does not contain a unique identifier, you have to provide an additional - * setting (@ref MY_SIGNING_SOFT_SERIAL) for all nodes that communicate to a node which has whitelisting enabled. Example: + * The "soft" backend of course also support whitelisting. Example: * @code{.cpp} * #define MY_SIGNING_SOFT - * #define MY_SIGNING_SOFT_SERIAL 0x12,0x34,0x56,0x78,0x90,0x12,0x34,0x56,0x78 * #define MY_SIGNING_SOFT_RANDOMSEED_PIN 7 - * #define MY_SIGNING_SOFT_HMAC_KEY 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xa0,0xb0,0xc0,0xd0,0xe0,0xf0,0x11,0x22 * #define MY_SIGNING_REQUEST_SIGNATURES * #define MY_SIGNING_NODE_WHITELISTING {{.nodeId = GATEWAY_ADDRESS,.serial = {0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01}},{.nodeId = 2,.serial = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09}}} * #include * ... * @endcode * - * For a node that should transmit whitelisted messages but not receive whitelisted messages, you do not need any special configurations except to define - * a unique serial if using the software backend: + * For a node that should transmit whitelisted messages but not receive whitelisted messages, you do not need any special configurations: * @code{.cpp} * #define MY_SIGNING_SOFT - * #define MY_SIGNING_SOFT_SERIAL 0x12,0x34,0x56,0x78,0x90,0x12,0x34,0x56,0x78 * #define MY_SIGNING_SOFT_RANDOMSEED_PIN 7 - * #define MY_SIGNING_SOFT_HMAC_KEY 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xa0,0xb0,0xc0,0xd0,0xe0,0xf0,0x11,0x22 * @endcode * Remember that you always need to select a signing backend for all nodes that communicate to a node that require whitelisting. * Also, note that a node that use whitelisting will not accept messages from nodes that are not present in it's whitelist. + * And you have to personalize all nodes that use signing with a common HMAC key but different serial numbers (ATSHA204A always has unique serials). * * @section MySigningtechnical The technical stuff * @@ -411,9 +421,7 @@ * Configuration example for a motion sensor:
* @code{.cpp} * #define MY_SIGNING_SOFT - * #define MY_SIGNING_SOFT_SERIAL 0x12,0x34,0x56,0x78,0x90,0x12,0x34,0x56,0x78 * #define MY_SIGNING_SOFT_RANDOMSEED_PIN 7 - * #define MY_SIGNING_SOFT_HMAC_KEY 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xa0,0xb0,0xc0,0xd0,0xe0,0xf0,0x11,0x22 * #define MY_SIGNING_REQUEST_SIGNATURES * #include * ... @@ -422,9 +430,7 @@ * The gateway needs to configured with a whitelist (and it have to have an entry for all nodes that send and/or require signed messages):
* @code{.cpp} * #define MY_SIGNING_SOFT - * #define MY_SIGNING_SOFT_SERIAL 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88 * #define MY_SIGNING_SOFT_RANDOMSEED_PIN 7 - * #define MY_SIGNING_SOFT_HMAC_KEY 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xa0,0xb0,0xc0,0xd0,0xe0,0xf0,0x11,0x22 * #define MY_SIGNING_REQUEST_SIGNATURES * #define MY_SIGNING_NODE_WHITELISTING {{.nodeId = MOTION_SENSOR_ID,.serial = {0x12,0x34,0x56,0x78,0x90,0x12,0x34,0x56,0x78}}} * #include @@ -446,9 +452,7 @@ * Configuration example for the door controller node (should require signing from anyone who wants to control it):
* @code{.cpp} * #define MY_SIGNING_SOFT - * #define MY_SIGNING_SOFT_SERIAL 0x12,0x34,0x56,0x78,0x90,0x12,0x34,0x56,0x78 * #define MY_SIGNING_SOFT_RANDOMSEED_PIN 7 - * #define MY_SIGNING_SOFT_HMAC_KEY 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xa0,0xb0,0xc0,0xd0,0xe0,0xf0,0x11,0x22 * #define MY_SIGNING_REQUEST_SIGNATURES * #define MY_SIGNING_NODE_WHITELISTING {{.nodeId = GATEWAY_ADDRESS,.serial = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88}},{.nodeId = KEYFOB_ID,.serial = {}}} * #include @@ -458,7 +462,7 @@ * @subsection MySigningsketches Relevant sketches * * - @ref SecureActuator.ino - * - @ref Sha204Personalizer.ino + * - @ref SecurityPersonalizer.ino */ /** diff --git a/libraries/MySensors/core/MySigningAtsha204.cpp b/libraries/MySensors/core/MySigningAtsha204.cpp index ce78678..61a1293 100644 --- a/libraries/MySensors/core/MySigningAtsha204.cpp +++ b/libraries/MySensors/core/MySigningAtsha204.cpp @@ -86,6 +86,9 @@ static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, #define DEBUG_SIGNING_PRINTBUF(str, buf, sz) #endif +void signerAtsha204Init(void) { +} + bool signerAtsha204CheckTimer(void) { if (_signing_verification_ongoing) { if (millis() < _signing_timestamp || millis() > _signing_timestamp + MY_VERIFICATION_TIMEOUT_MS) { diff --git a/libraries/MySensors/core/MySigningAtsha204Soft.cpp b/libraries/MySensors/core/MySigningAtsha204Soft.cpp index 2b89fac..037905a 100644 --- a/libraries/MySensors/core/MySigningAtsha204Soft.cpp +++ b/libraries/MySensors/core/MySigningAtsha204Soft.cpp @@ -40,11 +40,11 @@ unsigned long _signing_timestamp; bool _signing_verification_ongoing = false; uint8_t _signing_current_nonce[NONCE_NUMIN_SIZE_PASSTHROUGH]; uint8_t _signing_temp_message[32]; -static uint8_t _signing_hmac_key[32] = { MY_SIGNING_SOFT_HMAC_KEY }; +static uint8_t _signing_hmac_key[32]; uint8_t _signing_hmac[32]; extern uint8_t _doWhitelist[32]; -const uint8_t _signing_node_serial_info[SHA204_SERIAL_SZ] = {MY_SIGNING_SOFT_SERIAL}; +static uint8_t _signing_node_serial_info[9]; #ifdef MY_SIGNING_NODE_WHITELISTING const whitelist_entry_t _signing_whitelist[] = MY_SIGNING_NODE_WHITELISTING; #endif @@ -89,6 +89,14 @@ static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, #define DEBUG_SIGNING_PRINTBUF(str, buf, sz) #endif +void signerAtsha204SoftInit(void) { + // initialize pseudo-RNG + randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN)); + // Set secrets + hwReadConfigBlock((void*)_signing_hmac_key, (void*)EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS, 32); + hwReadConfigBlock((void*)_signing_node_serial_info, (void*)EEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9); +} + bool signerAtsha204SoftCheckTimer(void) { if (_signing_verification_ongoing) { if (millis() < _signing_timestamp || millis() > _signing_timestamp + MY_VERIFICATION_TIMEOUT_MS) { diff --git a/libraries/MySensors/core/MyTransportNRF24.cpp b/libraries/MySensors/core/MyTransportNRF24.cpp index 1a62766..3d2ac1d 100644 --- a/libraries/MySensors/core/MyTransportNRF24.cpp +++ b/libraries/MySensors/core/MyTransportNRF24.cpp @@ -38,7 +38,7 @@ uint8_t _address; #if defined(MY_RF24_ENABLE_ENCRYPTION) AES _aes; uint8_t _dataenc[32] = {0}; - uint8_t _psk[] = { MY_RF24_ENCRYPTKEY }; + uint8_t _psk[16]; #endif bool transportInit() { @@ -65,7 +65,9 @@ bool transportInit() { #if defined(MY_RF24_ENABLE_ENCRYPTION) + hwReadConfigBlock((void*)_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); _aes.set_key(_psk, 16); //set up AES-key + memset(_psk, 0, 16); // Make sure it is purged from memory when set #endif //_rf24.printDetails(); diff --git a/libraries/MySensors/core/MyTransportRFM69.cpp b/libraries/MySensors/core/MyTransportRFM69.cpp index f6ded5f..35305ce 100644 --- a/libraries/MySensors/core/MyTransportRFM69.cpp +++ b/libraries/MySensors/core/MyTransportRFM69.cpp @@ -30,7 +30,10 @@ bool transportInit() { // Start up the radio library (_address will be set later by the MySensors library) if (_radio.initialize(MY_RFM69_FREQUENCY, _address, MY_RFM69_NETWORKID)) { #ifdef MY_RFM69_ENABLE_ENCRYPTION - _radio.encrypt(RFM69_ENCRYPTKEY); + uint8_t _psk[16]; + hwReadConfigBlock((void*)_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); + _radio.encrypt(_psk); + memset(_psk, 0, 16); // Make sure it is purged from memory when set #endif return true; } diff --git a/libraries/MySensors/drivers/AES/AES.h b/libraries/MySensors/drivers/AES/AES.h index a37a1e5..1d92c8c 100644 --- a/libraries/MySensors/drivers/AES/AES.h +++ b/libraries/MySensors/drivers/AES/AES.h @@ -35,7 +35,7 @@ /* code was modified by george spanos * 16/12/14 */ - +/** AES class */ class AES { public: @@ -351,7 +351,7 @@ class AES * @defgroup aeslib AES library for Arduino and Raspberry pi * @ingroup internals * - * @section Goals design Goals + * @section AesGoals design Goals * * This library is AESigned to be... * @li Fast and efficient. @@ -393,10 +393,10 @@ class AES * cd examples_Rpi
* sudo ./\

* - * @section News News + * @section AesNews News * * If issues are discovered with the documentation, please report them here - * @section Useful Useful References + * @section AesUseful Useful References * * Please refer to: * @@ -405,7 +405,7 @@ class AES * @li Source Code * @li All spaniakos Documentation Main Page * - * @section Board_Support Board Support + * @section AesBoard_Support Board Support * * Most standard Arduino based boards are supported: * - Arduino diff --git a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino index 3e6c6bb..308b8e9 100644 --- a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino +++ b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino @@ -37,7 +37,6 @@ * is defined by @ref LOCK_1. The number of locks is controlled by @ref NOF_LOCKS .
* The sketch will require incoming messages to be signed and the use of signing backend is selected * by @ref MY_SIGNING_ATSHA204 or @ref MY_SIGNING_SOFT. Hard or soft ATSHA204 signing is supported.
- * If soft signing is chosen, make sure to use a correct HMAC key (see @ref MY_SIGNING_SOFT_HMAC_KEY).
* Whitelisting can be enabled through @ref MY_SIGNING_NODE_WHITELISTING in which case a single entry * is provided in this example which typically should map to the gateway of the network. */ @@ -60,11 +59,6 @@ // SETTINGS FOR MY_SIGNING_SOFT -/// Set the soft_serial value to an arbitrary value for proper security (9 bytes) -#define MY_SIGNING_SOFT_SERIAL 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09 -/// Key to use for HMAC calculation in soft signing (32 bytes) -#define MY_SIGNING_SOFT_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 - #define MY_SIGNING_SOFT_RANDOMSEED_PIN 7 //!< Unconnected analog pin for random seed // SETTINGS FOR MY_SIGNING_ATSHA204 diff --git a/libraries/MySensors/examples/Sha204Personalizer/Sha204Personalizer.ino b/libraries/MySensors/examples/SecurityPersonalizer/SecurityPersonalizer.ino similarity index 73% rename from libraries/MySensors/examples/Sha204Personalizer/Sha204Personalizer.ino rename to libraries/MySensors/examples/SecurityPersonalizer/SecurityPersonalizer.ino index 0634283..43e25be 100644 --- a/libraries/MySensors/examples/Sha204Personalizer/Sha204Personalizer.ino +++ b/libraries/MySensors/examples/SecurityPersonalizer/SecurityPersonalizer.ino @@ -21,16 +21,20 @@ /** * @ingroup MySigninggrp * @{ - * @file Sha204Personalizer.ino - * @brief SHA204 personalization sketch + * @file SecurityPersonalizer.ino + * @brief Security personalization sketch * * REVISION HISTORY - * - See git log (git log libraries/MySensors/examples/Sha204Personalizer/Sha204Personalizer.ino) + * - See git log (git log libraries/MySensors/examples/SecurityPersonalizer/SecurityPersonalizer.ino) */ /** - * @example Sha204Personalizer.ino - * This sketch will write factory default settings to the configuration zone + * @example SecurityPersonalizer.ino + * This sketch will personalize either none-volatile memory or ATSHA204A for security functions + * available in the MySensors library. + * + * For ATSHA204A: + * It will write factory default settings to the configuration zone * and then lock it.
* It will then either
* -# Generate a random value to use as a key which will be stored in @@ -45,13 +49,41 @@ * turn on the locking. Furthermore, user have to send a SPACE character on serial * console when prompted to do any locking. On boards that does not provide UART * input it is possible to configure the sketch to skip this confirmation. - * Default settings use ATSHA204 on @ref ATSHA204_PIN. + * Default settings use ATSHA204A on @ref MY_SIGNING_ATSHA204_PIN. + * + * For Soft signing: + * It will
+ * -# Generate a random value to use as a key which will be stored in EEPROM. + * The key is printed on UART (115200) in clear text for the user to be ablle to + * use it as a user-supplied key in other personalization executions where the same + * key is needed. + * -# Use a user-supplied value to use as a key which will be stored in EEPROM. + * -# Generate a random value to use as a serial number which will be stored in EEPROM. + * The serial number is printed on UART (115200) in clear text for the user to be ablle to + * use it as a user-supplied serial number in other personalization executions where the + * serial is needed (typically for a whitelist). + * -# Use a user-supplied value to use as a serial which will be stored in EEPROM. + * + * For Encryption support: + * -# Generate a random value to use as a AES key which will be stored in EEPROM. + * The AES key is printed on UART (115200) in clear text for the user to be ablle to + * use it as a user-supplied AES key in other personalization executions where the + * AES key is needed (typically for RF encryption). + * -# Use a user-supplied value to use as a AES key which will be stored in EEPROM. + * + * Personalizing EEPROM or ATSHA204A still require the appropriate configuration of the + * library to actually have an effect. There is no problem personalizing EEPROM and + * ATSHA204A at the same time. There is however a security risk with using the same + * data for EEPROM and ATSHA204A so it is recommended to use different serial and HMAC + * keys on the same device for ATSHA204A vs soft signing settings. * * Details on personalization procedure is given in @ref perzonalization. */ #include #include +#define MY_CORE_ONLY +#include // Doxygen specific constructs, not included when built normally // This is used to enable disabled macros/definitions to be included in the documentation as well. @@ -59,12 +91,17 @@ #define LOCK_CONFIGURATION #define LOCK_DATA #define SKIP_KEY_STORAGE -#define USER_KEY_DATA +#define USER_KEY #define SKIP_UART_CONFIRMATION +#define USE_SOFT_SIGNING +#define STORE_SOFT_KEY +#define USER_SOFT_KEY +#define STORE_SOFT_SERIAL +#define USER_SOFT_SERIAL +#define STORE_AES_KEY +#define USER_AES_KEY #endif -#define ATSHA204_PIN 17 //!< The pin the ATSHA204 is connected on (A3). - /** * @def LOCK_CONFIGURATION * @brief Uncomment this to enable locking the configuration zone. @@ -89,13 +126,13 @@ * @def SKIP_KEY_STORAGE * @brief Uncomment this to skip key storage (typically once key has been written once) */ -//#define SKIP_KEY_STORAGE +#define SKIP_KEY_STORAGE /** - * @def USER_KEY_DATA + * @def USER_KEY * @brief Uncomment this to skip key generation and use @ref user_key_data as key instead. */ -//#define USER_KEY_DATA +//#define USER_KEY /** * @def SKIP_UART_CONFIRMATION @@ -106,19 +143,84 @@ */ //#define SKIP_UART_CONFIRMATION -#if defined(SKIP_UART_CONFIRMATION) && !defined(USER_KEY_DATA) -#error You have to define USER_KEY_DATA for boards that does not have UART +/** + * @def USE_SOFT_SIGNING + * @brief Uncomment this to store data to EEPROM instead of ATSHA204A + */ +//#define USE_SOFT_SIGNING + +/** + * @def STORE_SOFT_KEY + * @brief Uncomment this to store soft HMAC key to EEPROM + */ +//#define STORE_SOFT_KEY + +/** + * @def USER_SOFT_KEY + * @brief Uncomment this to skip soft HMAC key generation and use @ref user_soft_key_data as HMAC key instead. + */ +//#define USER_SOFT_KEY + +/** + * @def STORE_SOFT_SERIAL + * @brief Uncomment this to store soft serial to EEPROM + */ +//#define STORE_SOFT_SERIAL + +/** + * @def USER_SOFT_SERIAL + * @brief Uncomment this to skip soft serial generation and use @ref user_soft_serial as serial instead. + */ +//#define USER_SOFT_SERIAL + +/** + * @def STORE_AES_KEY + * @brief Uncomment this to store AES key to EEPROM + */ +//#define STORE_AES_KEY + +/** + * @def USER_AES_KEY + * @brief Uncomment this to skip AES key generation and use @ref user_aes_key as key instead. + */ +//#define USER_AES_KEY + +#if defined(SKIP_UART_CONFIRMATION) && !defined(USER_KEY) +#error You have to define USER_KEY for boards that does not have UART #endif -#ifdef USER_KEY_DATA +#ifdef USER_KEY /** @brief The user-defined HMAC key to use for personalization */ #define MY_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 /** @brief The data to store in key slot 0 */ const uint8_t user_key_data[32] = {MY_HMAC_KEY}; #endif -const int sha204Pin = ATSHA204_PIN; //!< The IO pin to use for ATSHA204 +#ifdef USER_SOFT_KEY +/** @brief The user-defined soft HMAC key to use for EEPROM personalization */ +#define MY_SOFT_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +/** @brief The data to store as soft HMAC key in EEPROM */ +const uint8_t user_soft_key_data[32] = {MY_SOFT_HMAC_KEY}; +#endif + +#ifdef USER_SOFT_SERIAL +/** @brief The user-defined soft serial to use for EEPROM personalization */ +#define MY_SOFT_SERIAL 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +/** @brief The data to store as soft serial in EEPROM */ +const uint8_t user_soft_serial[9] = {MY_SOFT_SERIAL}; +#endif + +#ifdef USER_AES_KEY +/** @brief The user-defined AES key to use for EEPROM personalization */ +#define MY_AES_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +/** @brief The data to store as AES key in EEPROM */ +const uint8_t user_aes_key[16] = {MY_AES_KEY}; +#endif + +#ifndef USE_SOFT_SIGNING +const int sha204Pin = MY_SIGNING_ATSHA204_PIN; //!< The IO pin to use for ATSHA204A atsha204Class sha204(sha204Pin); +#endif /** @brief Print a error notice and halt the execution */ void halt() @@ -127,6 +229,7 @@ void halt() while(1); } +#ifndef USE_SOFT_SIGNING /** * @brief Write default configuration and return CRC of the configuration bits * @returns CRC over the configuration bits @@ -275,14 +378,53 @@ void write_key(uint8_t* key) halt(); } } +#endif // not USE_SOFT_SIGNING /** @brief Dump current configuration to UART */ void dump_configuration() { + uint8_t buffer[32]; +#ifndef USE_SOFT_SIGNING + Serial.println(F("EEPROM DATA:")); +#endif + hwReadConfigBlock((void*)buffer, (void*)EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS, 32); + Serial.print(F("SOFT_HMAC_KEY | ")); + for (int j=0; j<32; j++) + { + if (buffer[j] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(buffer[j], HEX); + } + Serial.println(); + hwReadConfigBlock((void*)buffer, (void*)EEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9); + Serial.print(F("SOFT_SERIAL | ")); + for (int j=0; j<9; j++) + { + if (buffer[j] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(buffer[j], HEX); + } + Serial.println(); + hwReadConfigBlock((void*)buffer, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); + Serial.print(F("AES_KEY | ")); + for (int j=0; j<16; j++) + { + if (buffer[j] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(buffer[j], HEX); + } + Serial.println(); +#ifndef USE_SOFT_SIGNING uint8_t tx_buffer[SHA204_CMD_SIZE_MAX]; uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; uint8_t ret_code; - + Serial.println(F("ATSHA204A DATA:")); for (int i=0; i < 88; i += 4) { ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, i); @@ -712,25 +854,36 @@ void dump_configuration() Serial.println(); } } +#endif // not USE_SOFT_SIGNING } /** @brief Sketch setup code */ void setup() { + // Delay startup a bit for serial consoles to catch up + unsigned long enter = hwMillis(); + while (hwMillis() - enter < (unsigned long)500); +#ifndef USE_SOFT_SIGNING uint8_t tx_buffer[SHA204_CMD_SIZE_MAX]; uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; - uint8_t key[32]; uint8_t ret_code; uint8_t lockConfig = 0; uint8_t lockValue = 0; uint16_t crc; (void)crc; +#else + // initialize pseudo-RNG + randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN)); +#endif + uint8_t key[32]; + (void)key; Serial.begin(115200); - Serial.println(F("ATSHA204 personalization sketch for MySensors usage.")); - Serial.println(F("----------------------------------------------------")); + Serial.println(F("Personalization sketch for MySensors usage.")); + Serial.println(F("-------------------------------------------")); +#ifndef USE_SOFT_SIGNING // Wake device before starting operations ret_code = sha204.sha204c_wakeup(rx_buffer); if (ret_code != SHA204_SUCCESS) @@ -738,7 +891,171 @@ void setup() Serial.print(F("Failed to wake device. Response: ")); Serial.println(ret_code, HEX); halt(); } + // Read out lock config bits to determine if locking is possible + ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, 0x15<<2); + if (ret_code != SHA204_SUCCESS) + { + Serial.print(F("Failed to determine device lock status. Response: ")); Serial.println(ret_code, HEX); + halt(); + } + else + { + lockConfig = rx_buffer[SHA204_BUFFER_POS_DATA+3]; + lockValue = rx_buffer[SHA204_BUFFER_POS_DATA+2]; + } +#endif +#ifdef STORE_SOFT_KEY +#ifdef USER_SOFT_KEY + memcpy(key, user_soft_key_data, 32); + Serial.println(F("Using this user supplied soft HMAC key:")); +#else + // Retrieve random value to use as soft HMAC key +#ifdef USE_SOFT_SIGNING + for (int i = 0; i < 32; i++) { + key[i] = random(256) ^ micros(); + unsigned long enter = hwMillis(); + while (hwMillis() - enter < (unsigned long)2); + } + Serial.println(F("This value will be stored in EEPROM as soft HMAC key:")); +#else + ret_code = sha204.sha204m_random(tx_buffer, rx_buffer, RANDOM_SEED_UPDATE); + if (ret_code != SHA204_SUCCESS) + { + Serial.print(F("Random key generation failed. Response: ")); Serial.println(ret_code, HEX); + halt(); + } + else + { + memcpy(key, rx_buffer+SHA204_BUFFER_POS_DATA, 32); + } + if (lockConfig == 0x00) + { + Serial.println(F("This value will be stored in EEPROM as soft HMAC key:")); + } + else + { + Serial.println(F("Key is not randomized (configuration not locked):")); + } +#endif // not USE_SOFT_SIGNING +#endif // not USER_SOFT_KEY + Serial.print("#define MY_SOFT_HMAC_KEY "); + for (int i=0; i<32; i++) + { + Serial.print("0x"); + if (key[i] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(key[i], HEX); + if (i < 31) Serial.print(','); + } + Serial.println(); + hwWriteConfigBlock((void*)key, (void*)EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS, 32); +#endif // STORE_SOFT_KEY + +#ifdef STORE_SOFT_SERIAL +#ifdef USER_SOFT_SERIAL + memcpy(key, user_soft_serial, 9); + Serial.println(F("Using this user supplied soft serial:")); +#else + // Retrieve random value to use as serial +#ifdef USE_SOFT_SIGNING + for (int i = 0; i < 9; i++) { + key[i] = random(256) ^ micros(); + unsigned long enter = hwMillis(); + while (hwMillis() - enter < (unsigned long)2); + } + Serial.println(F("This value will be stored in EEPROM as soft serial:")); +#else + ret_code = sha204.sha204m_random(tx_buffer, rx_buffer, RANDOM_SEED_UPDATE); + if (ret_code != SHA204_SUCCESS) + { + Serial.print(F("Random serial generation failed. Response: ")); Serial.println(ret_code, HEX); + halt(); + } + else + { + memcpy(key, rx_buffer+SHA204_BUFFER_POS_DATA, 9); + } + if (lockConfig == 0x00) + { + Serial.println(F("This value will be stored in EEPROM as soft serial:")); + } + else + { + Serial.println(F("Serial is not randomized (configuration not locked):")); + } +#endif // not USE_SOFT_SIGNING +#endif // not USER_SOFT_SERIAL + Serial.print("#define MY_SOFT_SERIAL "); + for (int i=0; i<9; i++) + { + Serial.print("0x"); + if (key[i] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(key[i], HEX); + if (i < 8) Serial.print(','); + } + Serial.println(); + hwWriteConfigBlock((void*)key, (void*)EEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9); +#endif // STORE_SOFT_SERIAL + +#ifdef STORE_AES_KEY +#ifdef USER_AES_KEY + memcpy(key, user_aes_key, 16); + Serial.println(F("Using this user supplied AES key:")); +#else + // Retrieve random value to use as key +#ifdef USE_SOFT_SIGNING + for (int i = 0; i < 16; i++) { + key[i] = random(256) ^ micros(); + unsigned long enter = hwMillis(); + while (hwMillis() - enter < (unsigned long)2); + } + Serial.println(F("This key will be stored in EEPROM as AES key:")); +#else + ret_code = sha204.sha204m_random(tx_buffer, rx_buffer, RANDOM_SEED_UPDATE); + if (ret_code != SHA204_SUCCESS) + { + Serial.print(F("Random key generation failed. Response: ")); Serial.println(ret_code, HEX); + halt(); + } + else + { + memcpy(key, rx_buffer+SHA204_BUFFER_POS_DATA, 32); + } + if (lockConfig == 0x00) + { + Serial.println(F("This key will be stored in EEPROM as AES key:")); + } + else + { + Serial.println(F("Key is not randomized (configuration not locked):")); + } +#endif // not USE_SOFT_SIGNING +#endif // not USER_AES_KEY + Serial.print("#define MY_AES_KEY "); + for (int i=0; i<16; i++) + { + Serial.print("0x"); + if (key[i] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(key[i], HEX); + if (i < 15) Serial.print(','); + } + Serial.println(); + hwWriteConfigBlock((void*)key, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); +#endif // STORE_AES_KEY + +#ifdef USE_SOFT_SIGNING + Serial.println(F("EEPROM configuration:")); + dump_configuration(); +#else // Output device revision on console ret_code = sha204.sha204m_dev_rev(tx_buffer, rx_buffer); if (ret_code != SHA204_SUCCESS) @@ -794,19 +1111,6 @@ void setup() Serial.println(); } - // Read out lock config bits to determine if locking is possible - ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, 0x15<<2); - if (ret_code != SHA204_SUCCESS) - { - Serial.print(F("Failed to determine device lock status. Response: ")); Serial.println(ret_code, HEX); - halt(); - } - else - { - lockConfig = rx_buffer[SHA204_BUFFER_POS_DATA+3]; - lockValue = rx_buffer[SHA204_BUFFER_POS_DATA+2]; - } - if (lockConfig != 0x00) { // Write config and get CRC for the updated config @@ -886,9 +1190,9 @@ void setup() #ifdef SKIP_KEY_STORAGE Serial.println(F("Disable SKIP_KEY_STORAGE to store key.")); #else -#ifdef USER_KEY_DATA +#ifdef USER_KEY memcpy(key, user_key_data, 32); - Serial.println(F("Using this user supplied key:")); + Serial.println(F("Using this user supplied HMAC key:")); #else // Retrieve random value to use as key ret_code = sha204.sha204m_random(tx_buffer, rx_buffer, RANDOM_SEED_UPDATE); @@ -1022,9 +1326,11 @@ void setup() { Serial.println(F("Skipping OTP/data zone lock (zone already locked).")); } +#endif // not USE_SOFT_SIGNING Serial.println(F("--------------------------------")); Serial.println(F("Personalization is now complete.")); +#ifndef USE_SOFT_SIGNING Serial.print(F("Configuration is ")); if (lockConfig == 0x00) { @@ -1043,6 +1349,7 @@ void setup() { Serial.println("UNLOCKED"); } +#endif } /** @brief Sketch execution code */ diff --git a/libraries/MySensors/keywords.txt b/libraries/MySensors/keywords.txt index 257dcbf..fc148be 100644 --- a/libraries/MySensors/keywords.txt +++ b/libraries/MySensors/keywords.txt @@ -60,10 +60,7 @@ MY_VERIFICATION_TIMEOUT_MS LITERAL1 MY_SIGNING_NODE_WHITELISTING LITERAL1 MY_SIGNING_ATSHA204_PIN LITERAL1 MY_SIGNING_SOFT_RANDOMSEED_PIN LITERAL1 -MY_SIGNING_SOFT_SERIAL LITERAL1 -MY_SIGNING_SOFT_HMAC_KEY LITERAL1 MY_RF24_ENABLE_ENCRYPTION LITERAL1 -MY_RF24_ENCRYPTKEY LITERAL1 MY_RF24_CE_PIN LITERAL1 MY_RF24_CS_PIN LITERAL1 MY_RF24_PA_LEVEL LITERAL1 @@ -81,7 +78,7 @@ MY_RFM69_NETWORKID LITERAL1 MY_RF69_IRQ_PIN LITERAL1 MY_RF69_SPI_CS LITERAL1 MY_RF69_IRQ_NUM LITERAL1 -MY_RFM69_ENCRYPTKEY LITERAL1 +MY_RFM69_ENABLE_ENCRYPTION LITERAL1 MY_GATEWAY_SERIAL LITERAL1 MY_GATEWAY_W5100 LITERAL1 MY_GATEWAY_ENC28J60 LITERAL1