diff --git a/core/MyEepromAddresses.h b/core/MyEepromAddresses.h index 89a76f4..c067276 100644 --- a/core/MyEepromAddresses.h +++ b/core/MyEepromAddresses.h @@ -36,7 +36,8 @@ #define SIZE_PARENT_NODE_ID (1u) //!< Size parent node ID #define SIZE_DISTANCE (1u) //!< Size GW distance #define SIZE_ROUTES (256u) //!< Size routing table -#define SIZE_CONTROLLER_CONFIG (24u) //!< Size controller config +#define SIZE_CONTROLLER_CONFIG (23u) //!< Size controller config +#define SIZE_PERSONALIZATION_CHECKSUM (1u) //!< Size personalization checksum #define SIZE_FIRMWARE_TYPE (2u) //!< Size firmware type #define SIZE_FIRMWARE_VERSION (2u) //!< Size firmware version #define SIZE_FIRMWARE_BLOCKS (2u) //!< Size firmware blocks @@ -61,8 +62,10 @@ #define EEPROM_ROUTES_ADDRESS (EEPROM_DISTANCE_ADDRESS + SIZE_DISTANCE) /** @brief Address configuration bytes sent by controller */ #define EEPROM_CONTROLLER_CONFIG_ADDRESS (EEPROM_ROUTES_ADDRESS + SIZE_ROUTES) +/** @brief Personalization checksum (set by SecurityPersonalizer.ino) */ +#define EEPROM_PERSONALIZATION_CHECKSUM_ADDRESS (EEPROM_CONTROLLER_CONFIG_ADDRESS + SIZE_CONTROLLER_CONFIG) /** @brief Address firmware type */ -#define EEPROM_FIRMWARE_TYPE_ADDRESS (EEPROM_CONTROLLER_CONFIG_ADDRESS + SIZE_CONTROLLER_CONFIG) +#define EEPROM_FIRMWARE_TYPE_ADDRESS (EEPROM_PERSONALIZATION_CHECKSUM_ADDRESS + SIZE_PERSONALIZATION_CHECKSUM) /** @brief Address firmware version */ #define EEPROM_FIRMWARE_VERSION_ADDRESS (EEPROM_FIRMWARE_TYPE_ADDRESS + SIZE_FIRMWARE_TYPE) /** @brief Address firmware blocks */ diff --git a/core/MyHw.h b/core/MyHw.h index 3f08f42..971c09c 100644 --- a/core/MyHw.h +++ b/core/MyHw.h @@ -59,6 +59,11 @@ uint8_t hwReadConfig(int adr); typedef uint8_t unique_id_t[16]; +/** + * Sleep for a defined time, using minimum power. + * @param ms Time to sleep, in [ms]. + * @return -1. + */ int8_t hwSleep(unsigned long ms); /** diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index d2e9a0f..9292fb2 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -118,6 +118,7 @@ void _begin(void) ledsInit(); #endif + (void)signerValidatePersonalization(); signerInit(); // Read latest received controller configuration from EEPROM diff --git a/core/MySigning.cpp b/core/MySigning.cpp index efc03e5..c1680ec 100644 --- a/core/MySigning.cpp +++ b/core/MySigning.cpp @@ -62,7 +62,7 @@ enum { SIGN_WAITING_FOR_NONCE = 0, SIGN_OK = 1 }; #define CLEAR_WHITELIST(node) (_doWhitelist[node>>3]|=(1<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 SecurityPersonalizer.ino - * Note that you also need to do personalization for software signing, but then the values are stored in EEPROM (described below). + * Note that you also need to do personalization for software signing, but then the values are stored in EEPROM. * - * The process of personalizing the ATSHA204A involves - * - Writing and locking chip configuration - * - (optionally) Generating and (mandatory) writing HMAC key - * - (optionally) Locking data sections + * To personalize a ATSHA204A do the following procedure: + * 1. Enable @ref GENERATE_KEYS_ATSHA204A
+ * This will lock the ATSHA204A and generate random keys for HMAC (signing) and AES (encryption). + * Copy the keys generated and replace the corresponding definitions under + * "User defined key data", specifically @ref MY_HMAC_KEY and @ref MY_AES_KEY. + * 2. Disable @ref GENERATE_KEYS_ATSHA204A and enable @ref PERSONALIZE_ATSHA204A
+ * This will store the HMAC key to the ATSHA204A and the AES key to EEPROM. It will also write + * a checksum of the personalization data in EEPROM to be able to detect if the data is + * altered.
+ * Personalization is now complete. * - * First execute the sketch without modifications to make sure communications with the device can be established. It is highly recommended that - * the first time this is done, a device with serial debug possibilities is used.
- * When this has been confirmed, it is time to decide what type of personalization is desired.
- * There are a few options here.
- * Firstly, enable @ref LOCK_CONFIGURATION to allow the sketch to lock the chip configuration. The sketch will write the default settings to the - * chip because these are fine for our purposes. This also enables the RNG which is required to allow the sketch to automatically generate a PSK - * 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, 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 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 - * this irreversible operation is done. However, if a number of nodes are to undergo personalization, this option can be enabled to streamline - * the personalization.
- * This is a condensed description of settings to fully personalize and lock down a set of sensors (and gateways): - * - Pick a “master” device with serial debug port. - * - Set the following sketch configuration of the personalizer: - * -# Enable @ref LOCK_CONFIGURATION - * -# Disable @ref LOCK_DATA - * -# Enable @ref SKIP_KEY_STORAGE - * -# Disable @ref SKIP_UART_CONFIRMATION - * -# 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: - * -# Enable @ref LOCK_CONFIGURATION - * -# Enable @ref LOCK_DATA (if you are sure you do not need to replace/revoke the key, this is the most secure option to protect from key readout\n - * 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 - * - 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. + * To personalize for software signing do the following procedure: + * 1. Enable @ref GENERATE_KEYS_SOFT
+ * This will generate random keys for HMAC (signing) and AES (encryption). + * Copy the keys generated and replace the corresponding definitions under + * "User defined key data", specifically @ref MY_HMAC_KEY and @ref MY_AES_KEY. + * 2. Disable @ref GENERATE_KEYS_SOFT and enable @ref PERSONALIZE_SOFT
+ * This will store the HMAC key and the AES key to EEPROM. It will also write + * a checksum of the personalization data in EEPROM to be able to detect if the data is + * altered.
+ * Personalization is now complete. * - * 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) + * If you want to use soft signing and you want to use whitelisting (the ability to revoke/ban + * compromised nodes in the network) and your target does not provide a unique device ID, you have + * to generate a unique serial and store it in EEPROM. This can be done by replacing + * @ref PERSONALIZE_SOFT in step 2 above with @ref PERSONALIZE_SOFT_RANDOM_SERIAL. See the output + * under "Hardware security peripherals" to determine if this is necessary. * - * 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. + * When you have personalized your first device after step 2 above, you can run the same sketch on + * all devices in your network that needs to be personalized in a compatible manner. Pick + * @ref PERSONALIZE_ATSHA204A or @ref PERSONALIZE_SOFT as needed by the hardware. * * If a node does require signing, any unsigned message sent to the node will be rejected.
* This also applies to the gateway. However, the difference is that the gateway will only require signed messages from nodes it knows in turn @@ -499,6 +462,16 @@ typedef struct { */ void signerInit(void); +/** + * @brief Validates personalization data + * + * This function checks that the personalization details are in order. + * \n@b Usage: This fuction should be called before any signing related operations take place. + * + * @returns @c true if personalization data is valid. + */ +bool signerValidatePersonalization(void); + /** * @brief Does signing specific presentation for a node. * diff --git a/core/MySigningAtsha204.cpp b/core/MySigningAtsha204.cpp index 24fb29d..c013df5 100644 --- a/core/MySigningAtsha204.cpp +++ b/core/MySigningAtsha204.cpp @@ -27,7 +27,13 @@ #include "MySigning.h" -#define SIGNING_IDENTIFIER (1) +#define SIGNING_IDENTIFIER (1) //HMAC-SHA256 + +#if defined(MY_DEBUG_VERBOSE_SIGNING) +#define SIGN_DEBUG(x,...) hwDebugPrint(x, ##__VA_ARGS__) +#else +#define SIGN_DEBUG(x,...) +#endif // Define MY_DEBUG_VERBOSE_SIGNING in your sketch to enable signing backend debugprints @@ -47,59 +53,36 @@ const whitelist_entry_t _signing_whitelist[] = MY_SIGNING_NODE_WHITELISTING; static void signerCalculateSignature(MyMessage &msg, bool signing); static uint8_t* signerSha256(const uint8_t* data, size_t sz); +static bool init_ok = false; -#ifdef MY_DEBUG_VERBOSE_SIGNING -static char i2h(uint8_t i) -{ - uint8_t k = i & 0x0F; - if (k <= 9) { - return '0' + k; - } else { - return 'A' + k - 10; - } -} - -static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, uint8_t sz) -{ - static char printBuffer[300]; - if (NULL == buf) { - return; - } -#ifdef MY_GATEWAY_FEATURE - // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) - snprintf_P(printBuffer, 299, PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE); - MY_SERIALDEVICE.print(printBuffer); -#endif - for (int i=0; i> 4); - printBuffer[(i * 2) + 1] = i2h(buf[i]); - } - printBuffer[sz * 2] = '\0'; -#ifdef MY_GATEWAY_FEATURE - // Truncate message if this is gateway node - printBuffer[MY_GATEWAY_MAX_SEND_LENGTH-1-strlen_P((const char*)str)] = '\0'; -#endif - MY_SERIALDEVICE.print(str); - if (sz > 0) { - MY_SERIALDEVICE.print(printBuffer); - } - MY_SERIALDEVICE.println(""); -} -#else -#define DEBUG_SIGNING_PRINTBUF(str, buf, sz) -#endif - -void signerAtsha204Init(void) +bool signerAtsha204Init(void) { + init_ok = true; atsha204_init(MY_SIGNING_ATSHA204_PIN); + + (void)atsha204_wakeup(_signing_temp_message); + // Read the configuration lock flag to determine if device is personalized or not + if (atsha204_read(_signing_tx_buffer, _signing_rx_buffer, + SHA204_ZONE_CONFIG, 0x15<<2) != SHA204_SUCCESS) { + SIGN_DEBUG(PSTR("Could not read ATSHA204A lock config, refusing to use backend\n")); + init_ok = false; + } else if (_signing_rx_buffer[SHA204_BUFFER_POS_DATA+3] != 0x00) { + SIGN_DEBUG(PSTR("ATSHA204A not personalized, refusing to use backend\n")); + init_ok = false; + } + return init_ok; } bool signerAtsha204CheckTimer(void) { + if (!init_ok) { + SIGN_DEBUG(PSTR("Backend not initialized\n")); + return false; + } if (_signing_verification_ongoing) { if (hwMillis() < _signing_timestamp || hwMillis() > _signing_timestamp + MY_VERIFICATION_TIMEOUT_MS) { - DEBUG_SIGNING_PRINTBUF(F("Verification timeout"), NULL, 0); + SIGN_DEBUG(PSTR("Verification timeout\n")); // Purge nonce memset(_signing_signing_nonce, 0x00, NONCE_NUMIN_SIZE_PASSTHROUGH); memset(_signing_verifying_nonce, 0x00, NONCE_NUMIN_SIZE_PASSTHROUGH); @@ -112,14 +95,18 @@ bool signerAtsha204CheckTimer(void) bool signerAtsha204GetNonce(MyMessage &msg) { - DEBUG_SIGNING_PRINTBUF(F("Signing backend: ATSHA204"), NULL, 0); + if (!init_ok) { + SIGN_DEBUG(PSTR("Backend not initialized\n")); + return false; + } + SIGN_DEBUG(PSTR("Signing backend: ATSHA204\n")); // Generate random number for use as nonce // We used a basic whitening technique that XORs each byte in a 32byte random value with current hwMillis() counter // This 32-byte random value is then hashed (SHA256) to produce the resulting nonce (void)atsha204_wakeup(_signing_temp_message); if (atsha204_execute(SHA204_RANDOM, RANDOM_SEED_UPDATE, 0, 0, NULL, RANDOM_COUNT, _signing_tx_buffer, RANDOM_RSP_SIZE, _signing_rx_buffer) != SHA204_SUCCESS) { - DEBUG_SIGNING_PRINTBUF(F("Failed to generate nonce"), NULL, 0); + SIGN_DEBUG(PSTR("Failed to generate nonce\n")); return false; } for (int i = 0; i < 32; i++) { @@ -147,7 +134,11 @@ bool signerAtsha204GetNonce(MyMessage &msg) void signerAtsha204PutNonce(MyMessage &msg) { - DEBUG_SIGNING_PRINTBUF(F("Signing backend: ATSHA204"), NULL, 0); + if (!init_ok) { + SIGN_DEBUG(PSTR("Backend not initialized\n")); + return; + } + SIGN_DEBUG(PSTR("Signing backend: ATSHA204\n")); memcpy(_signing_signing_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 @@ -158,7 +149,7 @@ 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); + SIGN_DEBUG(PSTR("Message too large\n")); return false; } @@ -174,7 +165,10 @@ bool signerAtsha204SignMsg(MyMessage &msg) atsha204_getSerialNumber(&_signing_signing_nonce[33]); (void)signerSha256(_signing_signing_nonce, 32+1+SHA204_SERIAL_SZ); // we can 'void' sha256 because the hash is already put in the correct place - DEBUG_SIGNING_PRINTBUF(F("Signature salted with serial"), NULL, 0); + SIGN_DEBUG(PSTR("Signature salted with serial: %02X%02X%02X%02X%02X%02X%02X%02X%02X\n"), + _signing_signing_nonce[33], _signing_signing_nonce[34], _signing_signing_nonce[35], + _signing_signing_nonce[36], _signing_signing_nonce[37], _signing_signing_nonce[38], + _signing_signing_nonce[39], _signing_signing_nonce[40], _signing_signing_nonce[41]); } // Put device back to sleep @@ -186,8 +180,6 @@ bool signerAtsha204SignMsg(MyMessage &msg) // Transfer as much signature data as the remaining space in the message permits memcpy(&msg.data[mGetLength(msg)], &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg)); - DEBUG_SIGNING_PRINTBUF(F("Signature in message: "), (uint8_t*)&msg.data[mGetLength(msg)], - MAX_PAYLOAD-mGetLength(msg)); return true; } @@ -195,7 +187,7 @@ bool signerAtsha204SignMsg(MyMessage &msg) bool signerAtsha204VerifyMsg(MyMessage &msg) { if (!_signing_verification_ongoing) { - DEBUG_SIGNING_PRINTBUF(F("No active verification session"), NULL, 0); + SIGN_DEBUG(PSTR("No active verification session\n")); return false; } else { // Make sure we have not expired @@ -206,12 +198,10 @@ bool signerAtsha204VerifyMsg(MyMessage &msg) _signing_verification_ongoing = false; if (msg.data[mGetLength(msg)] != SIGNING_IDENTIFIER) { - DEBUG_SIGNING_PRINTBUF(F("Incorrect signing identifier"), NULL, 0); + SIGN_DEBUG(PSTR("Incorrect signing identifier\n")); return false; } - DEBUG_SIGNING_PRINTBUF(F("Signature in message: "), (uint8_t*)&msg.data[mGetLength(msg)], - MAX_PAYLOAD-mGetLength(msg)); signerCalculateSignature(msg, false); // Get signature of message #ifdef MY_SIGNING_NODE_WHITELISTING @@ -219,7 +209,7 @@ bool signerAtsha204VerifyMsg(MyMessage &msg) size_t j; for (j=0; j < NUM_OF(_signing_whitelist); j++) { if (_signing_whitelist[j].nodeId == msg.sender) { - DEBUG_SIGNING_PRINTBUF(F("Sender found in whitelist"), NULL, 0); + SIGN_DEBUG(PSTR("Sender found in whitelist\n")); memcpy(_signing_verifying_nonce, &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], 32); // We can reuse the nonce buffer now since it is no longer needed _signing_verifying_nonce[32] = msg.sender; @@ -230,7 +220,7 @@ bool signerAtsha204VerifyMsg(MyMessage &msg) } } if (j == NUM_OF(_signing_whitelist)) { - DEBUG_SIGNING_PRINTBUF(F("Sender not found in whitelist, message rejected!"), NULL, 0); + SIGN_DEBUG(PSTR("Sender not found in whitelist, message rejected!\n")); // Put device back to sleep atsha204_sleep(); return false; @@ -246,14 +236,13 @@ bool signerAtsha204VerifyMsg(MyMessage &msg) // Compare the caluclated signature with the provided signature if (signerMemcmp(&msg.data[mGetLength(msg)], &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg))) { - DEBUG_SIGNING_PRINTBUF(F("Signature bad: "), &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], - MAX_PAYLOAD-mGetLength(msg)); + SIGN_DEBUG(PSTR("Signature bad\n")); #ifdef MY_SIGNING_NODE_WHITELISTING - DEBUG_SIGNING_PRINTBUF(F("Is the sender whitelisted and serial correct?"), NULL, 0); + SIGN_DEBUG(PSTR("Is the sender whitelisted and serial correct?\n")); #endif return false; } else { - DEBUG_SIGNING_PRINTBUF(F("Signature OK"), NULL, 0); + SIGN_DEBUG(PSTR("Signature OK\n")); return true; } } @@ -268,10 +257,42 @@ static void signerCalculateSignature(MyMessage &msg, bool signing) MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); // Program the data to sign into the ATSHA204 - DEBUG_SIGNING_PRINTBUF(F("Message to process: "), (uint8_t*)&msg.data[1-HEADER_SIZE], - MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); - DEBUG_SIGNING_PRINTBUF(F("Current nonce: "), - signing ? _signing_signing_nonce : _signing_verifying_nonce, 32); + SIGN_DEBUG(PSTR("Current nonce: " + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n"), + signing ? _signing_signing_nonce[0] : _signing_verifying_nonce[0], + signing ? _signing_signing_nonce[1] : _signing_verifying_nonce[1], + signing ? _signing_signing_nonce[2] : _signing_verifying_nonce[2], + signing ? _signing_signing_nonce[3] : _signing_verifying_nonce[3], + signing ? _signing_signing_nonce[4] : _signing_verifying_nonce[4], + signing ? _signing_signing_nonce[5] : _signing_verifying_nonce[5], + signing ? _signing_signing_nonce[6] : _signing_verifying_nonce[6], + signing ? _signing_signing_nonce[7] : _signing_verifying_nonce[7], + signing ? _signing_signing_nonce[8] : _signing_verifying_nonce[8], + signing ? _signing_signing_nonce[9] : _signing_verifying_nonce[9], + signing ? _signing_signing_nonce[10] : _signing_verifying_nonce[10], + signing ? _signing_signing_nonce[11] : _signing_verifying_nonce[11], + signing ? _signing_signing_nonce[12] : _signing_verifying_nonce[12], + signing ? _signing_signing_nonce[13] : _signing_verifying_nonce[13], + signing ? _signing_signing_nonce[14] : _signing_verifying_nonce[14], + signing ? _signing_signing_nonce[15] : _signing_verifying_nonce[15], + signing ? _signing_signing_nonce[16] : _signing_verifying_nonce[16], + signing ? _signing_signing_nonce[17] : _signing_verifying_nonce[17], + signing ? _signing_signing_nonce[18] : _signing_verifying_nonce[18], + signing ? _signing_signing_nonce[19] : _signing_verifying_nonce[19], + signing ? _signing_signing_nonce[20] : _signing_verifying_nonce[20], + signing ? _signing_signing_nonce[21] : _signing_verifying_nonce[21], + signing ? _signing_signing_nonce[22] : _signing_verifying_nonce[22], + signing ? _signing_signing_nonce[23] : _signing_verifying_nonce[23], + signing ? _signing_signing_nonce[24] : _signing_verifying_nonce[24], + signing ? _signing_signing_nonce[25] : _signing_verifying_nonce[25], + signing ? _signing_signing_nonce[26] : _signing_verifying_nonce[26], + signing ? _signing_signing_nonce[27] : _signing_verifying_nonce[27], + signing ? _signing_signing_nonce[28] : _signing_verifying_nonce[28], + signing ? _signing_signing_nonce[29] : _signing_verifying_nonce[29], + signing ? _signing_signing_nonce[30] : _signing_verifying_nonce[30], + signing ? _signing_signing_nonce[31] : _signing_verifying_nonce[31] + ); (void)atsha204_execute(SHA204_WRITE, SHA204_ZONE_DATA | SHA204_ZONE_COUNT_FLAG, 8 << 3, 32, _signing_temp_message, WRITE_COUNT_LONG, _signing_tx_buffer, WRITE_RSP_SIZE, _signing_rx_buffer); @@ -293,7 +314,42 @@ static void signerCalculateSignature(MyMessage &msg, bool signing) (void)atsha204_execute(SHA204_HMAC, HMAC_MODE_SOURCE_FLAG_MATCH, 0, 0, NULL, HMAC_COUNT, _signing_tx_buffer, HMAC_RSP_SIZE, _signing_rx_buffer); - DEBUG_SIGNING_PRINTBUF(F("HMAC: "), &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], 32); + SIGN_DEBUG(PSTR("HMAC: " + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n"), + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+0], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+1], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+2], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+3], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+4], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+5], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+6], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+7], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+8], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+9], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+10], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+11], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+12], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+13], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+14], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+15], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+16], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+17], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+18], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+19], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+20], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+21], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+22], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+23], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+24], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+25], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+26], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+27], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+28], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+29], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+30], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+31] + ); } // Helper to calculate a generic SHA256 digest of provided buffer (only supports one block) @@ -314,6 +370,41 @@ static uint8_t* signerSha256(const uint8_t* data, size_t sz) (void)atsha204_execute(SHA204_SHA, SHA_CALC, 0, SHA_MSG_SIZE, _signing_temp_message, SHA_COUNT_LONG, _signing_tx_buffer, SHA_RSP_SIZE_LONG, _signing_rx_buffer); - DEBUG_SIGNING_PRINTBUF(F("SHA256: "), &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], 32); + SIGN_DEBUG(PSTR("SHA256: " + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n"), + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+0], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+1], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+2], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+3], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+4], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+5], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+6], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+7], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+8], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+9], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+10], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+11], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+12], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+13], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+14], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+15], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+16], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+17], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+18], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+19], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+20], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+21], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+22], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+23], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+24], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+25], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+26], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+27], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+28], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+29], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+30], + _signing_rx_buffer[SHA204_BUFFER_POS_DATA+31] + ); return &_signing_rx_buffer[SHA204_BUFFER_POS_DATA]; } diff --git a/core/MySigningAtsha204Soft.cpp b/core/MySigningAtsha204Soft.cpp index b564317..dc9645a 100644 --- a/core/MySigningAtsha204Soft.cpp +++ b/core/MySigningAtsha204Soft.cpp @@ -31,7 +31,13 @@ #include "MySigning.h" #include "drivers/ATSHA204/sha256.h" -#define SIGNING_IDENTIFIER (1) +#define SIGNING_IDENTIFIER (1) //HMAC-SHA256 + +#if defined(MY_DEBUG_VERBOSE_SIGNING) +#define SIGN_DEBUG(x,...) hwDebugPrint(x, ##__VA_ARGS__) +#else +#define SIGN_DEBUG(x,...) +#endif // Define MY_DEBUG_VERBOSE_SIGNING in your sketch to enable signing backend debugprints @@ -52,69 +58,39 @@ const whitelist_entry_t _signing_whitelist[] = MY_SIGNING_NODE_WHITELISTING; static void signerCalculateSignature(MyMessage &msg, bool signing); -#ifdef MY_DEBUG_VERBOSE_SIGNING -static char i2h(uint8_t i) -{ - uint8_t k = i & 0x0F; - if (k <= 9) { - return '0' + k; - } else { - return 'A' + k - 10; - } -} +static bool init_ok = false; +static const uint8_t reset_serial[9] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; -#ifdef __linux__ -#define __FlashStringHelper char -#define MY_SERIALDEVICE.print debug -#endif - -static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, uint8_t sz) +bool signerAtsha204SoftInit(void) { - static char printBuffer[300]; - if (NULL == buf) { - return; - } -#if defined(MY_GATEWAY_FEATURE) && !defined(__linux__) - // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) - snprintf_P(printBuffer, 299, PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE); - MY_SERIALDEVICE.print(printBuffer); -#endif - for (int i=0; i> 4); - printBuffer[(i * 2) + 1] = i2h(buf[i]); - } - printBuffer[sz * 2] = '\0'; -#if defined(MY_GATEWAY_FEATURE) && !defined(__linux__) - // Truncate message if this is gateway node - printBuffer[MY_GATEWAY_MAX_SEND_LENGTH-1-strlen_P((const char*)str)] = '\0'; -#endif - MY_SERIALDEVICE.print(str); - if (sz > 0) { - MY_SERIALDEVICE.print(printBuffer); - } -#if !defined(__linux__) - MY_SERIALDEVICE.println(""); -#endif -} -#else -#define DEBUG_SIGNING_PRINTBUF(str, buf, sz) -#endif + init_ok = true; -void signerAtsha204SoftInit(void) -{ // initialize pseudo-RNG hwRandomNumberInit(); // 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); + if (!memcmp(_signing_node_serial_info, reset_serial, 9)) { + unique_id_t uniqueID; + // There is no serial, attempt to get unique ID for serial instead + if (hwUniqueID(&uniqueID)) { + // There is a unique serial, use that + memcpy(_signing_node_serial_info, uniqueID, 9); + } + } + return init_ok; } bool signerAtsha204SoftCheckTimer(void) { + if (!init_ok) { + SIGN_DEBUG(PSTR("Backend not initialized\n")); + return false; + } if (_signing_verification_ongoing) { if (hwMillis() < _signing_timestamp || hwMillis() > _signing_timestamp + MY_VERIFICATION_TIMEOUT_MS) { - DEBUG_SIGNING_PRINTBUF(F("Verification timeout"), NULL, 0); + SIGN_DEBUG(PSTR("Verification timeout\n")); // Purge nonce memset(_signing_signing_nonce, 0xAA, 32); memset(_signing_verifying_nonce, 0xAA, 32); @@ -127,7 +103,11 @@ bool signerAtsha204SoftCheckTimer(void) bool signerAtsha204SoftGetNonce(MyMessage &msg) { - DEBUG_SIGNING_PRINTBUF(F("Signing backend: ATSHA204Soft"), NULL, 0); + if (!init_ok) { + SIGN_DEBUG(PSTR("Backend not initialized\n")); + return false; + } + SIGN_DEBUG(PSTR("Signing backend: ATSHA204Soft\n")); // We used a basic whitening technique that XORs a random byte with the current hwMillis() counter and then the byte is // hashed (SHA256) to produce the resulting nonce @@ -136,7 +116,6 @@ bool signerAtsha204SoftGetNonce(MyMessage &msg) _signing_sha256.write(random(256) ^ (hwMillis()&0xFF)); } memcpy(_signing_verifying_nonce, _signing_sha256.result(), MAX_PAYLOAD); - DEBUG_SIGNING_PRINTBUF(F("SHA256: "), _signing_verifying_nonce, 32); // We set the part of the 32-byte nonce that does not fit into a message to 0xAA memset(&_signing_verifying_nonce[MAX_PAYLOAD], 0xAA, sizeof(_signing_verifying_nonce)-MAX_PAYLOAD); @@ -156,7 +135,10 @@ bool signerAtsha204SoftGetNonce(MyMessage &msg) void signerAtsha204SoftPutNonce(MyMessage &msg) { - DEBUG_SIGNING_PRINTBUF(F("Signing backend: ATSHA204Soft"), NULL, 0); + if (!init_ok) { + SIGN_DEBUG(PSTR("Backend not initialized\n")); + } + SIGN_DEBUG(PSTR("Signing backend: ATSHA204Soft\n")); memcpy(_signing_signing_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 @@ -167,7 +149,7 @@ 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); + SIGN_DEBUG(PSTR("Message too large\n")); return false; } @@ -186,8 +168,10 @@ bool signerAtsha204SoftSignMsg(MyMessage &msg) _signing_sha256.write(_signing_node_serial_info[i]); } memcpy(_signing_hmac, _signing_sha256.result(), 32); - DEBUG_SIGNING_PRINTBUF(F("SHA256: "), _signing_hmac, 32); - DEBUG_SIGNING_PRINTBUF(F("Signature salted with serial"), NULL, 0); + SIGN_DEBUG(PSTR("Signature salted with serial: %02X%02X%02X%02X%02X%02X%02X%02X%02X\n"), + _signing_node_serial_info[0], _signing_node_serial_info[1], _signing_node_serial_info[2], + _signing_node_serial_info[3], _signing_node_serial_info[4], _signing_node_serial_info[5], + _signing_node_serial_info[6], _signing_node_serial_info[7], _signing_node_serial_info[8]); } // Overwrite the first byte in the signature with the signing identifier @@ -195,8 +179,6 @@ bool signerAtsha204SoftSignMsg(MyMessage &msg) // Transfer as much signature data as the remaining space in the message permits memcpy(&msg.data[mGetLength(msg)], _signing_hmac, MAX_PAYLOAD-mGetLength(msg)); - DEBUG_SIGNING_PRINTBUF(F("Signature in message: "), (uint8_t*)&msg.data[mGetLength(msg)], - MAX_PAYLOAD-mGetLength(msg)); return true; } @@ -204,7 +186,7 @@ bool signerAtsha204SoftSignMsg(MyMessage &msg) bool signerAtsha204SoftVerifyMsg(MyMessage &msg) { if (!_signing_verification_ongoing) { - DEBUG_SIGNING_PRINTBUF(F("No active verification session"), NULL, 0); + SIGN_DEBUG(PSTR("No active verification session\n")); return false; } else { // Make sure we have not expired @@ -215,21 +197,18 @@ bool signerAtsha204SoftVerifyMsg(MyMessage &msg) _signing_verification_ongoing = false; if (msg.data[mGetLength(msg)] != SIGNING_IDENTIFIER) { - DEBUG_SIGNING_PRINTBUF(F("Incorrect signing identifier"), NULL, 0); + SIGN_DEBUG(PSTR("Incorrect signing identifier\n")); return false; } - // Get signature of message - DEBUG_SIGNING_PRINTBUF(F("Signature in message: "), (uint8_t*)&msg.data[mGetLength(msg)], - MAX_PAYLOAD-mGetLength(msg)); - signerCalculateSignature(msg, false); + signerCalculateSignature(msg, false); // Get signature of message #ifdef MY_SIGNING_NODE_WHITELISTING // Look up the senders nodeId in our whitelist and salt the signature with that data size_t j; for (j=0; j < NUM_OF(_signing_whitelist); j++) { if (_signing_whitelist[j].nodeId == msg.sender) { - DEBUG_SIGNING_PRINTBUF(F("Sender found in whitelist"), NULL, 0); + SIGN_DEBUG(PSTR("Sender found in whitelist\n")); _signing_sha256.init(); for (int i=0; i<32; i++) { _signing_sha256.write(_signing_hmac[i]); @@ -239,12 +218,11 @@ bool signerAtsha204SoftVerifyMsg(MyMessage &msg) _signing_sha256.write(_signing_whitelist[j].serial[i]); } memcpy(_signing_hmac, _signing_sha256.result(), 32); - DEBUG_SIGNING_PRINTBUF(F("SHA256: "), _signing_hmac, 32); break; } } if (j == NUM_OF(_signing_whitelist)) { - DEBUG_SIGNING_PRINTBUF(F("Sender not found in whitelist, message rejected!"), NULL, 0); + SIGN_DEBUG(PSTR("Sender not found in whitelist, message rejected!\n")); return false; } #endif @@ -254,13 +232,13 @@ bool signerAtsha204SoftVerifyMsg(MyMessage &msg) // Compare the caluclated signature with the provided signature if (signerMemcmp(&msg.data[mGetLength(msg)], _signing_hmac, MAX_PAYLOAD-mGetLength(msg))) { - DEBUG_SIGNING_PRINTBUF(F("Signature bad: "), _signing_hmac, MAX_PAYLOAD-mGetLength(msg)); + SIGN_DEBUG(PSTR("Signature bad\n")); #ifdef MY_SIGNING_NODE_WHITELISTING - DEBUG_SIGNING_PRINTBUF(F("Is the sender whitelisted and serial correct?"), NULL, 0); + SIGN_DEBUG(PSTR("Is the sender whitelisted and serial correct?\n")); #endif return false; } else { - DEBUG_SIGNING_PRINTBUF(F("Signature OK"), NULL, 0); + SIGN_DEBUG(PSTR("Signature OK\n")); return true; } } @@ -272,10 +250,42 @@ static void signerCalculateSignature(MyMessage &msg, bool signing) 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))); - DEBUG_SIGNING_PRINTBUF(F("Current nonce: "), - signing ? _signing_signing_nonce : _signing_verifying_nonce, 32); + SIGN_DEBUG(PSTR("Current nonce: " + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n"), + signing ? _signing_signing_nonce[0] : _signing_verifying_nonce[0], + signing ? _signing_signing_nonce[1] : _signing_verifying_nonce[1], + signing ? _signing_signing_nonce[2] : _signing_verifying_nonce[2], + signing ? _signing_signing_nonce[3] : _signing_verifying_nonce[3], + signing ? _signing_signing_nonce[4] : _signing_verifying_nonce[4], + signing ? _signing_signing_nonce[5] : _signing_verifying_nonce[5], + signing ? _signing_signing_nonce[6] : _signing_verifying_nonce[6], + signing ? _signing_signing_nonce[7] : _signing_verifying_nonce[7], + signing ? _signing_signing_nonce[8] : _signing_verifying_nonce[8], + signing ? _signing_signing_nonce[9] : _signing_verifying_nonce[9], + signing ? _signing_signing_nonce[10] : _signing_verifying_nonce[10], + signing ? _signing_signing_nonce[11] : _signing_verifying_nonce[11], + signing ? _signing_signing_nonce[12] : _signing_verifying_nonce[12], + signing ? _signing_signing_nonce[13] : _signing_verifying_nonce[13], + signing ? _signing_signing_nonce[14] : _signing_verifying_nonce[14], + signing ? _signing_signing_nonce[15] : _signing_verifying_nonce[15], + signing ? _signing_signing_nonce[16] : _signing_verifying_nonce[16], + signing ? _signing_signing_nonce[17] : _signing_verifying_nonce[17], + signing ? _signing_signing_nonce[18] : _signing_verifying_nonce[18], + signing ? _signing_signing_nonce[19] : _signing_verifying_nonce[19], + signing ? _signing_signing_nonce[20] : _signing_verifying_nonce[20], + signing ? _signing_signing_nonce[21] : _signing_verifying_nonce[21], + signing ? _signing_signing_nonce[22] : _signing_verifying_nonce[22], + signing ? _signing_signing_nonce[23] : _signing_verifying_nonce[23], + signing ? _signing_signing_nonce[24] : _signing_verifying_nonce[24], + signing ? _signing_signing_nonce[25] : _signing_verifying_nonce[25], + signing ? _signing_signing_nonce[26] : _signing_verifying_nonce[26], + signing ? _signing_signing_nonce[27] : _signing_verifying_nonce[27], + signing ? _signing_signing_nonce[28] : _signing_verifying_nonce[28], + signing ? _signing_signing_nonce[29] : _signing_verifying_nonce[29], + signing ? _signing_signing_nonce[30] : _signing_verifying_nonce[30], + signing ? _signing_signing_nonce[31] : _signing_verifying_nonce[31] + ); // ATSHA204 calculates the HMAC with a PSK and a SHA256 digest of the following data: // 32 bytes zeroes @@ -348,5 +358,15 @@ static void signerCalculateSignature(MyMessage &msg, bool signing) memcpy(_signing_hmac, _signing_sha256.resultHmac(), 32); - DEBUG_SIGNING_PRINTBUF(F("HMAC: "), _signing_hmac, 32); + SIGN_DEBUG(PSTR("HMAC: " + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n"), + _signing_hmac[0], _signing_hmac[1], _signing_hmac[2], _signing_hmac[3], + _signing_hmac[4], _signing_hmac[5], _signing_hmac[6], _signing_hmac[7], + _signing_hmac[8], _signing_hmac[9], _signing_hmac[10], _signing_hmac[11], + _signing_hmac[12], _signing_hmac[13], _signing_hmac[14], _signing_hmac[15], + _signing_hmac[16], _signing_hmac[17], _signing_hmac[18], _signing_hmac[19], + _signing_hmac[20], _signing_hmac[21], _signing_hmac[22], _signing_hmac[23], + _signing_hmac[24], _signing_hmac[25], _signing_hmac[26], _signing_hmac[27], + _signing_hmac[28], _signing_hmac[29], _signing_hmac[30], _signing_hmac[31]); } diff --git a/drivers/ATSHA204/ATSHA204.cpp b/drivers/ATSHA204/ATSHA204.cpp index 3de63c9..030b8eb 100644 --- a/drivers/ATSHA204/ATSHA204.cpp +++ b/drivers/ATSHA204/ATSHA204.cpp @@ -14,7 +14,6 @@ static uint8_t swi_receive_bytes(uint8_t count, uint8_t *buffer); static uint8_t swi_send_bytes(uint8_t count, uint8_t *buffer); static uint8_t swi_send_byte(uint8_t value); static uint8_t sha204p_receive_response(uint8_t size, uint8_t *response); -static uint8_t sha204m_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address); static uint8_t sha204c_resync(uint8_t size, uint8_t *response); static uint8_t sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer, uint8_t execution_delay, uint8_t execution_timeout); @@ -373,27 +372,6 @@ static uint8_t sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uin return ret_code; } - -/* Marshaling functions */ - -static uint8_t sha204m_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address) -{ - uint8_t rx_size; - - address >>= 2; - - tx_buffer[SHA204_COUNT_IDX] = READ_COUNT; - tx_buffer[SHA204_OPCODE_IDX] = SHA204_READ; - tx_buffer[READ_ZONE_IDX] = zone; - tx_buffer[READ_ADDR_IDX] = (uint8_t) (address & SHA204_ADDRESS_MASK); - tx_buffer[READ_ADDR_IDX + 1] = 0; - - rx_size = (zone & SHA204_ZONE_COUNT_FLAG) ? READ_32_RSP_SIZE : READ_4_RSP_SIZE; - - return sha204c_send_and_receive(&tx_buffer[0], rx_size, &rx_buffer[0], READ_DELAY, - READ_EXEC_MAX - READ_DELAY); -} - /* CRC Calculator and Checker */ static void sha204c_calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc) @@ -574,14 +552,14 @@ uint8_t atsha204_getSerialNumber(uint8_t * response) uint8_t readResponse[READ_4_RSP_SIZE]; /* read from bytes 0->3 of config zone */ - uint8_t returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN03); + uint8_t returnCode = atsha204_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN03); if (!returnCode) { for (int i=0; i<4; i++) {// store bytes 0-3 into respones array response[i] = readResponse[SHA204_BUFFER_POS_DATA+i]; } /* read from bytes 8->11 of config zone */ - returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN47); + returnCode = atsha204_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN47); for (int i=4; i<8; i++) {// store bytes 4-7 of SN into response array response[i] = readResponse[SHA204_BUFFER_POS_DATA+(i-4)]; @@ -589,10 +567,28 @@ uint8_t atsha204_getSerialNumber(uint8_t * response) if (!returnCode) { /* Finally if last two reads were successful, read byte 8 of the SN */ - returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN8); + returnCode = atsha204_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN8); response[8] = readResponse[SHA204_BUFFER_POS_DATA]; // Byte 8 of SN should always be 0xEE } } return returnCode; } + +uint8_t atsha204_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address) +{ + uint8_t rx_size; + + address >>= 2; + + tx_buffer[SHA204_COUNT_IDX] = READ_COUNT; + tx_buffer[SHA204_OPCODE_IDX] = SHA204_READ; + tx_buffer[READ_ZONE_IDX] = zone; + tx_buffer[READ_ADDR_IDX] = (uint8_t) (address & SHA204_ADDRESS_MASK); + tx_buffer[READ_ADDR_IDX + 1] = 0; + + rx_size = (zone & SHA204_ZONE_COUNT_FLAG) ? READ_32_RSP_SIZE : READ_4_RSP_SIZE; + + return sha204c_send_and_receive(&tx_buffer[0], rx_size, &rx_buffer[0], READ_DELAY, + READ_EXEC_MAX - READ_DELAY); +} diff --git a/drivers/ATSHA204/ATSHA204.h b/drivers/ATSHA204/ATSHA204.h index 94b4171..76462f6 100644 --- a/drivers/ATSHA204/ATSHA204.h +++ b/drivers/ATSHA204/ATSHA204.h @@ -247,6 +247,7 @@ uint8_t atsha204_execute(uint8_t op_code, uint8_t param1, uint16_t param2, uint8_t datalen1, uint8_t *data1, uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer); uint8_t atsha204_getSerialNumber(uint8_t *response); +uint8_t atsha204_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address); #endif #endif diff --git a/drivers/SPIFlash/SPIFlash.cpp b/drivers/SPIFlash/SPIFlash.cpp index f142766..1347f28 100644 --- a/drivers/SPIFlash/SPIFlash.cpp +++ b/drivers/SPIFlash/SPIFlash.cpp @@ -290,11 +290,10 @@ void SPIFlash::writeBytes(uint32_t addr, const void* buf, uint16_t len) command(SPIFLASH_WRITEDISABLE); //end AAI programming unselect(); #else - uint16_t n; uint16_t maxBytes = 256-(addr%256); // force the first set of bytes to stay within the first page uint16_t offset = 0; while (len>0) { - n = (len<=maxBytes) ? len : maxBytes; + uint16_t n = (len<=maxBytes) ? len : maxBytes; command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program SPI.transfer(addr >> 16); SPI.transfer(addr >> 8); diff --git a/drivers/extEEPROM/extEEPROM.cpp b/drivers/extEEPROM/extEEPROM.cpp index ac3f80f..bc29275 100644 --- a/drivers/extEEPROM/extEEPROM.cpp +++ b/drivers/extEEPROM/extEEPROM.cpp @@ -122,16 +122,16 @@ byte extEEPROM::begin(twiClockFreq_t twiFreq) //from the Arduino Wire library is passed back through to the caller. byte extEEPROM::write(unsigned long addr, byte *values, unsigned int nBytes) { - uint8_t ctrlByte; //control byte (I2C device address & chip/block select bits) uint8_t txStatus = 0; //transmit status - uint16_t nWrite; //number of bytes to write - uint16_t nPage; //number of bytes remaining on current page, starting at addr if (addr + nBytes > _totalCapacity) { //will this write go past the top of the EEPROM? return EEPROM_ADDR_ERR; //yes, tell the caller } while (nBytes > 0) { + uint8_t ctrlByte; //control byte (I2C device address & chip/block select bits) + uint16_t nWrite; //number of bytes to write + uint16_t nPage; //number of bytes remaining on current page, starting at addr nPage = _pageSize - ( addr & (_pageSize - 1) ); //find min(nBytes, nPage, BUFFER_LENGTH) -- BUFFER_LENGTH is defined in the Wire library. nWrite = nBytes < nPage ? nBytes : nPage; @@ -178,16 +178,15 @@ byte extEEPROM::write(unsigned long addr, byte *values, unsigned int nBytes) //from the Arduino Wire library is passed back through to the caller. byte extEEPROM::read(unsigned long addr, byte *values, unsigned int nBytes) { - byte ctrlByte; - byte rxStatus; - uint16_t nRead; //number of bytes to read - uint16_t nPage; //number of bytes remaining on current page, starting at addr - if (addr + nBytes > _totalCapacity) { //will this read take us past the top of the EEPROM? return EEPROM_ADDR_ERR; //yes, tell the caller } while (nBytes > 0) { + byte ctrlByte; + byte rxStatus; + uint16_t nRead; //number of bytes to read + uint16_t nPage; //number of bytes remaining on current page, starting at addr nPage = _pageSize - ( addr & (_pageSize - 1) ); nRead = nBytes < nPage ? nBytes : nPage; nRead = BUFFER_LENGTH < nRead ? BUFFER_LENGTH : nRead; diff --git a/drivers/extEEPROM/extEEPROM.h b/drivers/extEEPROM/extEEPROM.h index 6ef0f7a..449c305 100644 --- a/drivers/extEEPROM/extEEPROM.h +++ b/drivers/extEEPROM/extEEPROM.h @@ -92,7 +92,7 @@ public: * @param pageSize * @param eepromAddr */ - extEEPROM(eeprom_size_t deviceCapacity, byte nDevice, unsigned int pageSize, + extEEPROM(eeprom_size_t deviceCapacity, byte nDevice, unsigned int pageSize, //!< extEEPROM() byte eepromAddr = 0x50); byte begin(twiClockFreq_t twiFreq = twiClock100kHz); //!< begin() byte write(unsigned long addr, byte *values, unsigned int nBytes); //!< write() diff --git a/examples/SecurityPersonalizer/SecurityPersonalizer.ino b/examples/SecurityPersonalizer/SecurityPersonalizer.ino index b03a724..3d9d2fb 100644 --- a/examples/SecurityPersonalizer/SecurityPersonalizer.ino +++ b/examples/SecurityPersonalizer/SecurityPersonalizer.ino @@ -31,147 +31,138 @@ /** * @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 - * slot 0. The key is printed on UART (115200) in clear text for the user to be - * able 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 - * slot 0. - * Finally it will lock the data zone. - * - * By default, no locking is performed. User have to manually enable the flags that - * 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 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 personalization. + * available in the MySensors library.
+ * Details on personalization procedure is given in @ref personalization.
+ * This sketch will when executed without modifications also print a guided workflow on the UART. */ #include "sha204_library.h" #include "sha204_lib_return_codes.h" +/** @brief Make use of the MySensors framework without invoking the entire system */ #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. -#if DOXYGEN -#define LOCK_CONFIGURATION -#define LOCK_DATA -#define SKIP_KEY_STORAGE -#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 +/************************************ User defined key data ***************************************/ + +/** @brief The user-defined HMAC key to use unless @ref GENERATE_HMAC_KEY is set */ +#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 user-defined AES key to store in EEPROM unless @ref GENERATE_AES_KEY is set */ +#define MY_AES_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + +/** @brief The user-defined soft serial to use for soft signing unless @ref GENERATE_SOFT_SERIAL is set */ +#define MY_SOFT_SERIAL 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF + +/***************************** Flags for guided personalization flow ******************************/ /** - * @def LOCK_CONFIGURATION - * @brief Uncomment this to enable locking the configuration zone. + * @def GENERATE_KEYS_ATSHA204A + * @brief Default settings for generating keys using ATSHA204A + * + * @note The generated keys displayed in the serial log with this setting needs to be written down + * and transferred to all nodes this gateway will communicate with. This is mandatory for ALL + * nodes for encryption (AES key). For signing (HMAC key) it is only required for nodes that + * use signing. Typically you set the values for @ref MY_HMAC_KEY and @ref MY_AES_KEY. + */ +//#define GENERATE_KEYS_ATSHA204A + +/** + * @def GENERATE_KEYS_SOFT + * @brief Default settings for generating keys using software + * + * @b Important
+ * You will need to ensure @ref MY_SIGNING_SOFT_RANDOMSEED_PIN is set to an unconnected analog pin + * in order to provide entropy to the software RNG. + * + * @note The generated keys displayed in the serial log with this setting needs to be written down + * and transferred to all nodes this gateway will communicate with. This is mandatory for ALL + * nodes for encryption (AES key). For signing (HMAC key) it is only required for nodes that + * use signing. Typically you set the values for @ref MY_HMAC_KEY and @ref MY_AES_KEY. + */ +//#define GENERATE_KEYS_SOFT + +/** + * @def PERSONALIZE_ATSHA204A + * @brief Default settings for personalizing an ATSHA204A + * + * It is assumed that you have updated @ref MY_HMAC_KEY and @ref MY_AES_KEY with the keys displayed + * when executing this sketch with @ref GENERATE_KEYS_ATSHA204A or @ref GENERATE_KEYS_SOFT defined. + */ +//#define PERSONALIZE_ATSHA204A + +/** + * @def PERSONALIZE_SOFT + * @brief Default settings for personalizing EEPROM for software signing + * + * It is assumed that you have updated @ref MY_HMAC_KEY and @ref MY_AES_KEY with the keys displayed + * when executing this sketch with @ref GENERATE_KEYS_ATSHA204A or @ref GENERATE_KEYS_SOFT defined. + */ +//#define PERSONALIZE_SOFT + +/** + * @def PERSONALIZE_SOFT_RANDOM_SERIAL + * @brief This is an alternative to @ref PERSONALIZE_SOFT which will also store a randomly generated + * serial to EEPROM in addition to the actions performed by @ref PERSONALIZE_SOFT. Take note of the + * generated soft serial as it will be needed if you plan to use whitelisting. It should be + * unique for each node. + * + * @note This is only needed for targets that lack unique device IDs. The sketch will inform you if + * there is a need for generating a random serial or not. Check the "Hardware security + * peripherals" listing. If a target has a unique device ID and a serial in EEPROM, the serial + * in EEPROM will be used. If erased (replaced with FF:es) the unique device ID will be used + * instead. + */ +//#define PERSONALIZE_SOFT_RANDOM_SERIAL + +/*************************** The settings below are for advanced users ****************************/ +/** + * @def USE_SOFT_SIGNING + * @brief Uncomment this to generate keys by software and store them to EEPROM instead of ATSHA204A + */ +//#define USE_SOFT_SIGNING + +/** + * @def LOCK_ATSHA204A_CONFIGURATION + * @brief Uncomment this to enable locking the ATSHA204A configuration zone * * It is still possible to change the key, and this also enable random key generation. * @warning BE AWARE THAT THIS PREVENTS ANY FUTURE CONFIGURATION CHANGE TO THE CHIP */ -//#define LOCK_CONFIGURATION - -/** - * @def LOCK_DATA - * @brief Uncomment this to enable locking the data zone. - * - * It is not required to lock data, key cannot be retrieved anyway, but by locking - * data, it can be guaranteed that nobody even with physical access to the chip, - * will be able to change the key. - * @warning BE AWARE THAT THIS PREVENTS THE KEY TO BE CHANGED - */ -//#define LOCK_DATA - -/** - * @def SKIP_KEY_STORAGE - * @brief Uncomment this to skip key storage (typically once key has been written once) - */ -#define SKIP_KEY_STORAGE - -/** - * @def USER_KEY - * @brief Uncomment this to skip key generation and use @ref user_key_data as key instead. - */ -//#define USER_KEY +//#define LOCK_ATSHA204A_CONFIGURATION /** * @def SKIP_UART_CONFIRMATION * @brief Uncomment this for boards that lack UART * - * @b Important
No confirmation will be required for locking any zones with this configuration! - * Also, key generation is not permitted in this mode as there is no way of presenting the generated key. + * This will disable additional confirmation for actions that are non-reversible. + * + * @b Important
For ATSHA204A, no confirmation will be required for locking any zones with this + * configuration! Also, if you generate keys on a board without UART, you have no way of determining + * what the key is unless it is stored in EEPROM. */ //#define SKIP_UART_CONFIRMATION /** - * @def USE_SOFT_SIGNING - * @brief Uncomment this to store data to EEPROM instead of ATSHA204A + * @def GENERATE_HMAC_KEY + * @brief Uncomment this to generate a random HMAC key using ATSHA204A or software depending on + * @ref USE_SOFT_SIGNING + * @note If not enabled, key defined by @ref MY_HMAC_KEY will be used instead. */ -//#define USE_SOFT_SIGNING +//#define GENERATE_HMAC_KEY /** - * @def STORE_SOFT_KEY - * @brief Uncomment this to store soft HMAC key to EEPROM + * @def STORE_HMAC_KEY + * @brief Uncomment this to store HMAC key to ATSHA204A or EEPROM depending on @ref USE_SOFT_SIGNING */ -//#define STORE_SOFT_KEY +//#define STORE_HMAC_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. + * @def GENERATE_AES_KEY + * @brief Uncomment this to generate a random AES key using ATSHA204A or software depending on + * @ref USE_SOFT_SIGNING + * @note If not enabled, key defined by @ref MY_AES_KEY will be used 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 +//#define GENERATE_AES_KEY /** * @def STORE_AES_KEY @@ -180,68 +171,807 @@ //#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. + * @def GENERATE_SOFT_SERIAL + * @brief Uncomment this to generate a random serial number for software signing + * @note If not enabled, serial defined by @ref MY_SOFT_SERIAL will be used instead. */ -//#define USER_AES_KEY +//#define GENERATE_SOFT_SERIAL -#if defined(SKIP_UART_CONFIRMATION) && !defined(USER_KEY) -#error You have to define USER_KEY for boards that does not have UART +/** + * @def STORE_SOFT_SERIAL + * @brief Uncomment this to store the serial number to EEPROM + */ +//#define STORE_SOFT_SERIAL + +/** + * @def PRINT_DETAILED_ATSHA204A_CONFIG + * @brief Uncomment to print the detailed ATSHA204A configuration + */ +//#define PRINT_DETAILED_ATSHA204A_CONFIG + +/** + * @def RESET_EEPROM_PERSONALIZATION + * @brief Uncomment to reset the personalization data in EEPROM to 0xFF:es + */ +//#define RESET_EEPROM_PERSONALIZATION + +/********************* Guided mode flag configurations (don't change these) ***********************/ +#ifdef GENERATE_KEYS_ATSHA204A +#define LOCK_ATSHA204A_CONFIGURATION // We have to lock configuration to enable random number generation +#define GENERATE_HMAC_KEY // Generate random HMAC key +#define GENERATE_AES_KEY // Generate random AES key +#define SKIP_UART_CONFIRMATION // This is an automated mode #endif -#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}; +#ifdef GENERATE_KEYS_SOFT +#define USE_SOFT_SIGNING // Use software backend +#define GENERATE_HMAC_KEY // Generate random HMAC key +#define GENERATE_AES_KEY // Generate random AES key +#define SKIP_UART_CONFIRMATION // This is an automated mode #endif -#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}; +#ifdef PERSONALIZE_ATSHA204A +#define LOCK_ATSHA204A_CONFIGURATION // We have to lock configuration to enable random number generation +#define STORE_HMAC_KEY // Store the HMAC key +#define STORE_AES_KEY // Store the AES key +#define SKIP_UART_CONFIRMATION // This is an automated mode #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 +#ifdef PERSONALIZE_SOFT_RANDOM_SERIAL +#define GENERATE_SOFT_SERIAL // Generate a soft serial number +#define PERSONALIZE_SOFT // Do the rest as PERSONALIZE_SOFT +#endif + +#ifdef PERSONALIZE_SOFT +#define USE_SOFT_SIGNING // Use software backend +#define STORE_HMAC_KEY // Store the HMAC key +#define STORE_AES_KEY // Store the AES key +#define STORE_SOFT_SERIAL // Store the soft serial number +#define SKIP_UART_CONFIRMATION // This is an automated mode +#endif + +#if defined(GENERATE_HMAC_KEY) || defined(GENERATE_AES_KEY) || defined(GENERATE_SOFT_SERIAL) +#define GENERATE_SOMETHING +#endif + +/********************************** Preprocessor sanitychecks *************************************/ +#if defined(GENERATE_SOFT_SERIAL) && !defined(USE_SOFT_SIGNING) +#error Cannot generate soft serial using ATSHA204A, use USE_SOFT_SINGING for this +#endif +#if defined(STORE_SOFT_SERIAL) && !defined(USE_SOFT_SIGNING) +#error Cannot store soft serial to ATSHA204A, use USE_SOFT_SINGING for this +#endif +#if defined(PRINT_DETAILED_ATSHA204A_CONFIG) && defined(USE_SOFT_SIGNING) +#error Cannot print ATSHA204A config using software signing flag, disable USE_SOFT_SINGING for this +#endif +#if defined(LOCK_ATSHA204A_CONFIGURATION) && defined(USE_SOFT_SIGNING) +#error Cannot lock ATSHA204A config using software signing flag, disable USE_SOFT_SINGING for this +#endif +#ifdef GENERATE_KEYS_ATSHA204A +#ifdef USE_SOFT_SIGNING +#error You cannot select soft signing if you want to generate keys using ATSHA204A +#endif +#ifdef STORE_HMAC_KEY +#error Disable STORE_SOFT_KEY, you should not store keys in this mode +#endif +#ifdef STORE_SOFT_SERIAL +#error Disable STORE_SOFT_SERIAL, you should not store serial in this mode +#endif +#ifdef STORE_AES_KEY +#error Disable STORE_AES_KEY, you should not store keys in this mode +#endif +#if defined(GENERATE_KEYS_SOFT) ||\ + defined (PERSONALIZE_ATSHA204A) ||\ + defined (PERSONALIZE_SOFT) ||\ + defined (PERSONALIZE_SOFT_RANDOM_SERIAL) +#error You can not enable GENERATE_KEYS_ATSHA204A together with other guided modes +#endif +#endif // GENERATE_KEYS_ATSHA204A +#ifdef GENERATE_KEYS_SOFT +#ifdef STORE_HMAC_KEY +#error Disable STORE_SOFT_KEY, you should not store keys in this mode +#endif +#ifdef STORE_SOFT_SERIAL +#error Disable STORE_SOFT_SERIAL, you should not store serial in this mode +#endif +#ifdef STORE_AES_KEY +#error Disable STORE_AES_KEY, you should not store keys in this mode +#endif +#ifndef MY_SIGNING_SOFT_RANDOMSEED_PIN +#error You have to set MY_SIGNING_SOFT_RANDOMSEED_PIN to a suitable value in this mode +#endif +#if defined(GENERATE_KEYS_ATSHA204A) ||\ + defined (PERSONALIZE_ATSHA204A) ||\ + defined (PERSONALIZE_SOFT) ||\ + defined (PERSONALIZE_SOFT_RANDOM_SERIAL) +#error You can not enable GENERATE_KEYS_SOFT together with other guided modes +#endif +#endif // GENERATE_KEYS_SOFT +#ifdef PERSONALIZE_ATSHA204A +#ifdef USE_SOFT_SIGNING +#error You cannot select soft signing if you want to personalize an ATSHA204A +#endif +#if defined(GENERATE_KEYS_ATSHA204A) ||\ + defined (GENERATE_KEYS_SOFT) ||\ + defined (PERSONALIZE_SOFT) ||\ + defined (PERSONALIZE_SOFT_RANDOM_SERIAL) +#error You can not enable PERSONALIZE_ATSHA204A together with other guided modes +#endif +#ifdef RESET_EEPROM_PERSONALIZATION +#error You cannot reset EEPROM personalization when personalizing a device +#endif +#endif // PERSONALIZE_ATSHA204A +#ifdef PERSONALIZE_SOFT +#if defined(GENERATE_KEYS_ATSHA204A) ||\ + defined (GENERATE_KEYS_SOFT) ||\ + defined (PERSONALIZE_ATSHA204A) +#error You can not enable PERSONALIZE_SOFT together with other guided modes +#endif +#ifdef RESET_EEPROM_PERSONALIZATION +#error You cannot reset EEPROM personalization when personalizing a device +#endif +#endif // PERSONALIZE_SOFT +#ifdef PERSONALIZE_SOFT_RANDOM_SERIAL +#if defined(GENERATE_KEYS_SOFT) ||\ + defined (PERSONALIZE_ATSHA204A) ||\ + defined (GENERATE_KEYS_ATSHA204A) +#error You can only enable one of the guided modes at a time +#endif +#ifdef RESET_EEPROM_PERSONALIZATION +#error You cannot reset EEPROM personalization when personalizing a device +#endif +#endif // PERSONALIZE_SOFT_RANDOM_SERIAL + +#if !defined(GENERATE_KEYS_ATSHA204A) &&\ + !defined(GENERATE_KEYS_SOFT) &&\ + !defined(PERSONALIZE_ATSHA204A) &&\ + !defined(PERSONALIZE_SOFT) &&\ + !defined(PERSONALIZE_SOFT_RANDOM_SERIAL) &&\ + !defined(USE_SOFT_SIGNING) &&\ + !defined(LOCK_ATSHA204A_CONFIGURATION) &&\ + !defined(SKIP_UART_CONFIRMATION) &&\ + !defined(GENERATE_HMAC_KEY) &&\ + !defined(STORE_HMAC_KEY) &&\ + !defined(GENERATE_SOFT_SERIAL) &&\ + !defined(STORE_SOFT_SERIAL) &&\ + !defined(GENERATE_AES_KEY) &&\ + !defined(STORE_AES_KEY) &&\ + !defined(PRINT_DETAILED_ATSHA204A_CONFIG) &&\ + !defined(RESET_EEPROM_PERSONALIZATION) +/** @brief Set when there are no config flags defined */ +#define NO_SETTINGS_DEFINED +#endif + +#if defined(GENERATE_KEYS_ATSHA204A) ||\ + defined(GENERATE_KEYS_SOFT) ||\ + defined(PERSONALIZE_ATSHA204A) ||\ + defined(PERSONALIZE_SOFT) ||\ + defined(PERSONALIZE_SOFT_RANDOM_SERIAL) +/** @brief Set when there is a guided mode flag defined */ +#define GUIDED_MODE +#endif + +/************************************* Function declarations ***************************************/ +static void halt(bool success); +#ifdef GENERATE_SOMETHING +static bool generate_random_data(uint8_t* data, size_t sz); +#endif +static void generate_keys(void); +static void store_keys(void); +static void print_hex_buffer(uint8_t* data, size_t sz); +static void print_c_friendly_hex_buffer(uint8_t* data, size_t sz); +#ifdef STORE_HMAC_KEY +static bool store_hmac_key_data(uint8_t* data, size_t sz); +#endif +#ifdef STORE_AES_KEY +static bool store_aes_key_data(uint8_t* data, size_t sz); +#endif +#ifdef STORE_SOFT_SERIAL +static bool store_soft_serial_data(uint8_t* data, size_t sz); +#endif +#ifndef USE_SOFT_SIGNING +static void init_atsha204a_state(void); +#ifdef LOCK_ATSHA204A_CONFIGURATION +static void lock_atsha204a_config(void); +static uint16_t write_atsha204a_config_and_get_crc(void); +#endif +static bool get_atsha204a_serial(uint8_t* data); +#ifdef STORE_HMAC_KEY +static bool write_atsha204a_key(uint8_t* key); +#endif +#endif // not USE_SOFT_SIGNING +static void print_greeting(void); +static void print_ending(void); +static void probe_and_print_peripherals(void); +static void print_eeprom_data(void); +static void print_whitelisting_entry(void); +#ifdef PRINT_DETAILED_ATSHA204A_CONFIG +static void dump_detailed_atsha204a_configuration(void); +#endif +#ifdef RESET_EEPROM_PERSONALIZATION +static void reset_eeprom(void); +#endif +static void write_eeprom_checksum(void); + +/**************************************** File local data *****************************************/ +#if defined(GENERATE_HMAC_KEY) || defined(STORE_HMAC_KEY) +/** @brief The data to store as HAMC key in ATSHA204A or EEPROM */ +static uint8_t user_hmac_key[32] = {MY_HMAC_KEY}; +#endif + +#if defined(GENERATE_SOFT_SERIAL) || defined(STORE_SOFT_SERIAL) /** @brief The data to store as soft serial in EEPROM */ -const uint8_t user_soft_serial[9] = {MY_SOFT_SERIAL}; +static 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}; +#if defined(GENERATE_AES_KEY) || defined(STORE_AES_KEY) +/* @brief The data to store as AES key in EEPROM */ +static 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); +static uint8_t tx_buffer[SHA204_CMD_SIZE_MAX]; +static uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; +static uint8_t ret_code; +static uint8_t lockConfig = 0; +static uint8_t lockValue = 0; +#endif +static bool has_device_unique_id = false; +static const uint8_t reset_buffer[32] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +/******************************************* Functions ********************************************/ + +/** @brief Sketch setup code (all personalization is done here as it is a run-once sketch) */ +void setup() +{ + // Delay startup a bit for serial consoles to catch up + unsigned long enter = hwMillis(); + while (hwMillis() - enter < (unsigned long)500); +#ifdef USE_SOFT_SIGNING + // initialize pseudo-RNG + randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN)); #endif -/** @brief Print a error notice and halt the execution */ -void halt() -{ - Serial.println(F("Halting!")); - while(1); -} + Serial.begin(MY_BAUD_RATE); + while(!Serial); // For USB enabled devices, wait for USB enumeration before continuing + hwInit(); + + print_greeting(); #ifndef USE_SOFT_SIGNING + init_atsha204a_state(); + // Lock configuration now if requested to enable RNG in ATSHA +#ifdef LOCK_ATSHA204A_CONFIGURATION + lock_atsha204a_config(); +#endif +#endif + // Generate the requested keys (if any) + generate_keys(); + +#ifdef RESET_EEPROM_PERSONALIZATION + // If requested, reset EEPROM before storing keys + reset_eeprom(); +#endif + + // Store the keys (if configured to do so) + store_keys(); + + // Write a checksum on the EEPROM data + write_eeprom_checksum(); + + // Print current EEPROM + print_eeprom_data(); + print_whitelisting_entry(); + Serial.println(); + + print_ending(); + halt(true); +} + +/** @brief Sketch execution code (unused) */ +void loop() +{ +} + +/** @brief Print a notice and halt the execution */ +static void halt(bool success) +{ + Serial.println(); + Serial.println( + F("+------------------------------------------------------------------------------------+")); + Serial.println( + F("| Execution result |")); + Serial.println( + F("+------------------------------------------------------------------------------------+")); + if (success) { + Serial.println(F( + "| SUCCESS |")); + } else { + Serial.print(F( + "| FAILURE ")); +#ifdef USE_SOFT_SIGNING + Serial.println(F(" |")); +#else + if (ret_code != SHA204_SUCCESS) { + Serial.print(F("(last ATSHA204A return code: 0x")); + if (ret_code < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(ret_code, HEX); + Serial.println(F(") |")); + } else { + Serial.println(F(" |")); + } +#endif + } + Serial.println( + F("+------------------------------------------------------------------------------------+")); + while(1) { + doYield(); + } +} + +#ifdef GENERATE_SOMETHING +/** + * @brief Generate random data of specified size and store in provided buffer + * @param data Buffer to store bytes in (buffer is assumed to be of required size) + * @param sz Number of random bytes to generate + * @returns false if failed + */ +static bool generate_random_data(uint8_t* data, size_t sz) +{ +#ifdef USE_SOFT_SIGNING + for (size_t i = 0; i < sz; i++) { + data[i] = random(256) ^ micros(); + unsigned long enter = hwMillis(); + while (hwMillis() - enter < (unsigned long)2); + } + return true; +#else + ret_code = sha204.sha204m_random(tx_buffer, rx_buffer, RANDOM_SEED_UPDATE); + if ((ret_code != SHA204_SUCCESS) || (lockConfig != 0x00)) { + return false; + } else { + memcpy(data, rx_buffer+SHA204_BUFFER_POS_DATA, sz); + return true; + } +#endif // not USE_SOFT_SIGNING +} +#endif // GENERATE_SOMETHING + +/** @brief Generate keys depending on configuration */ +static void generate_keys(void) +{ +#ifdef GENERATE_SOMETHING + Serial.println( + F("+------------------------------------------------------------------------------------+")); + Serial.println( + F("| Key generation |")); + Serial.println( + F("+--------+--------+------------------------------------------------------------------+")); + Serial.println( + F("| Key ID | Status | Key |")); + Serial.println( + F("+--------+--------+------------------------------------------------------------------+")); +#endif +#ifdef GENERATE_HMAC_KEY + Serial.print(F("| HMAC | ")); + if (!generate_random_data(user_hmac_key, 32)) { + memset(user_hmac_key, 0xFF, 32); + Serial.print(F("FAILED | ")); + } else { + Serial.print(F("OK | ")); + } + print_hex_buffer(user_hmac_key, 32); + Serial.println(F(" |")); +#endif +#ifdef GENERATE_AES_KEY + Serial.print(F("| AES | ")); + if (!generate_random_data(user_aes_key, 16)) { + memset(user_aes_key, 0xFF, 16); + Serial.print(F("FAILED | ")); + } else { + Serial.print(F("OK | ")); + } + print_hex_buffer(user_aes_key, 16); + Serial.println(F(" |")); +#endif +#ifdef GENERATE_SOFT_SERIAL + Serial.print(F("| SERIAL | ")); + if (has_device_unique_id) { + Serial.println(F("N/A | MCU has a unique serial which will be used instead. |")); + } else { + if (!generate_random_data(user_soft_serial, 9)) { + memset(user_soft_serial, 0xFF, 9); + Serial.print(F("FAILED | ")); + } else { + Serial.print(F("OK | ")); + } + print_hex_buffer(user_soft_serial, 9); + Serial.println(F(" |")); + } +#endif +#if defined(GENERATE_SOMETHING) && !defined(PERSONALIZE_SOFT_RANDOM_SERIAL) + Serial.println( + F("+--------+--------+------------------------------------------------------------------+")); + Serial.println(); + Serial.println( + F("+------------------------------------------------------------------------------------+")); + Serial.println( + F("| Key copy section |")); + Serial.println( + F("+------------------------------------------------------------------------------------+")); +#ifdef GENERATE_HMAC_KEY + Serial.print(F("#define MY_HMAC_KEY ")); + print_c_friendly_hex_buffer(user_hmac_key, 32); + Serial.println(); +#endif +#ifdef GENERATE_AES_KEY + Serial.print(F("#define MY_AES_KEY ")); + print_c_friendly_hex_buffer(user_aes_key, 16); + Serial.println(); +#endif +#ifdef GENERATE_SOFT_SERIAL + Serial.print(F("#define MY_SOFT_SERIAL ")); + print_c_friendly_hex_buffer(user_soft_serial, 9); + Serial.println(); +#endif + Serial.println( + F("+------------------------------------------------------------------------------------+")); + Serial.println(); +#elif defined(PERSONALIZE_SOFT_RANDOM_SERIAL) + Serial.println( + F("+--------+--------+------------------------------------------------------------------+")); + Serial.println(); +#endif +} + +#ifdef RESET_EEPROM_PERSONALIZATION +/** @brief Reset EEPROM */ +static void reset_eeprom(void) +{ + uint8_t validation_buffer[32]; + Serial.println( + F("+------------------------------------------------------------------------------------+")); + Serial.println( + F("| EEPROM reset |")); + Serial.println( + F("+--------+---------------------------------------------------------------------------+")); + Serial.println( + F("| Key ID | Status |")); + Serial.println( + F("+--------+---------------------------------------------------------------------------+")); + Serial.print(F("| HMAC | ")); + hwWriteConfigBlock((void*)reset_buffer, (void*)EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS, 32); + // Validate data written + hwReadConfigBlock((void*)validation_buffer, (void*)EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS, 32); + if (memcmp(validation_buffer, reset_buffer, 32) != 0) { + Serial.println(F("FAILED |")); + } else { + Serial.println(F("OK |")); + } + Serial.print(F("| AES | ")); + hwWriteConfigBlock((void*)reset_buffer, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); + // Validate data written + hwReadConfigBlock((void*)validation_buffer, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); + if (memcmp(validation_buffer, reset_buffer, 16) != 0) { + Serial.println(F("FAILED |")); + } else { + Serial.println(F("OK |")); + } + Serial.print(F("| SERIAL | ")); + hwWriteConfigBlock((void*)reset_buffer, (void*)EEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9); + // Validate data written + hwReadConfigBlock((void*)validation_buffer, (void*)EEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9); + if (memcmp(validation_buffer, reset_buffer, 9) != 0) { + Serial.println(F("FAILED |")); + } else { + Serial.println(F("OK |")); + } + Serial.println( + F("+--------+---------------------------------------------------------------------------+")); +} +#endif // RESET_EEPROM_PERSONALIZATION + +static void write_eeprom_checksum(void) +{ + uint8_t buffer[32]; + uint8_t* hash; + signerSha256Init(); + hwReadConfigBlock((void*)buffer, (void*)EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS, 32); + signerSha256Update(buffer, 32); + hwReadConfigBlock((void*)buffer, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); + signerSha256Update(buffer, 16); + hwReadConfigBlock((void*)buffer, (void*)EEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9); + signerSha256Update(buffer, 9); + hash = signerSha256Final(); + hwWriteConfigBlock((void*)&hash[0], (void*)EEPROM_PERSONALIZATION_CHECKSUM_ADDRESS, 1); +} + +/** @brief Store keys depending on configuration */ +static void store_keys(void) +{ +#if defined(STORE_HMAC_KEY) || defined(STORE_AES_KEY) || defined(STORE_SOFT_SERIAL) + Serial.println( + F("+------------------------------------------------------------------------------------+")); + Serial.println( + F("| Key storage |")); + Serial.println( + F("+--------+--------+------------------------------------------------------------------+")); + Serial.println( + F("| Key ID | Status | Key |")); + Serial.println( + F("+--------+--------+------------------------------------------------------------------+")); +#endif +#ifdef STORE_HMAC_KEY + Serial.print(F("| HMAC | ")); + if (!store_hmac_key_data(user_hmac_key)) { + Serial.print(F("FAILED | ")); + } else { + Serial.print(F("OK | ")); + } + print_hex_buffer(user_hmac_key, 32); + Serial.println(F(" |")); +#endif +#ifdef STORE_AES_KEY + Serial.print(F("| AES | ")); + if (!store_aes_key_data(user_aes_key)) { + Serial.print(F("FAILED | ")); + } else { + Serial.print(F("OK | ")); + } + print_hex_buffer(user_aes_key, 16); + Serial.println(F(" |")); +#endif +#ifdef STORE_SOFT_SERIAL + Serial.print(F("| SERIAL | ")); + if (has_device_unique_id) { + memset(user_soft_serial, 0xFF, 9); + } + if (!store_soft_serial_data(user_soft_serial)) { + Serial.print(F("FAILED | ")); + } else { + Serial.print(F("OK | ")); + } + if (has_device_unique_id) { + Serial.println(F("EEPROM reset. MCU has a unique serial which will be used instead.|")); + } else { + print_hex_buffer(user_soft_serial, 9); + Serial.println(F(" |")); + } +#endif +#if defined(STORE_HMAC_KEY) || defined(STORE_AES_KEY) || defined(STORE_SOFT_SERIAL) + Serial.println( + F("+--------+--------+------------------------------------------------------------------+")); + Serial.println(); +#endif +} + +/** + * @brief Print provided buffer as HEX data on serial console + * @param data Buffer to print + * @param sz Number of bytes to print + */ +static void print_hex_buffer(uint8_t* data, size_t sz) +{ + for (size_t i=0; i> 2, 4, config_word, 0, NULL, 0, NULL, WRITE_COUNT_SHORT, tx_buffer, WRITE_RSP_SIZE, rx_buffer); if (ret_code != SHA204_SUCCESS) { - Serial.print(F("Failed to write config word at address ")); - Serial.print(i); - Serial.print(F(". Response: ")); - Serial.println(ret_code, HEX); - halt(); + Serial.println( + F("+------------------------------------------------------------------------------------+")); + halt(false); } } } return crc; } +#endif +static bool get_atsha204a_serial(uint8_t* data) +{ + ret_code = sha204.getSerialNumber(rx_buffer); + if (ret_code != SHA204_SUCCESS) { + return false; + } else { + memcpy(data, rx_buffer, 9); + return true; + } +} + +#ifdef STORE_HMAC_KEY /** * @brief Write provided key to slot 0 * @param key The key data to write + * @returns false if failed */ -void write_key(uint8_t* key) +static bool write_atsha204a_key(uint8_t* key) { - uint8_t tx_buffer[SHA204_CMD_SIZE_MAX]; - uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; - uint8_t ret_code; - // Write key to slot 0 ret_code = sha204.sha204m_execute(SHA204_WRITE, SHA204_ZONE_DATA | SHA204_ZONE_COUNT_FLAG, 0, SHA204_ZONE_ACCESS_32, key, 0, NULL, 0, NULL, WRITE_COUNT_LONG, tx_buffer, WRITE_RSP_SIZE, rx_buffer); if (ret_code != SHA204_SUCCESS) { - Serial.print(F("Failed to write key to slot 0. Response: ")); - Serial.println(ret_code, HEX); - halt(); + return false; + } else { + return true; } } +#endif // STORE_HMAC_KEY #endif // not USE_SOFT_SIGNING -/** @brief Dump current configuration to UART */ -void dump_configuration() +/** @brief Print a greeting on serial console */ +static void print_greeting(void) +{ + Serial.println( + F("+------------------------------------------------------------------------------------+")); + Serial.println( + F("| MySensors security personalizer |")); + Serial.println( + F("+------------------------------------------------------------------------------------+")); + Serial.println(); +#ifdef NO_SETTINGS_DEFINED + Serial.println( + F("+------------------------------------------------------------------------------------+")); + Serial.println( + F("| You are running without any configuration flags set. |")); + Serial.println( + F("| No changes will be made to ATSHA204A or EEPROM except for the EEPROM checksum |")); + Serial.println( + F("| which will be updated. |")); + Serial.println( + F("| |")); + Serial.println( + F("| If you want to personalize your device, you have two options. |")); + Serial.println( + F("| |")); + Serial.println( + F("| 1. a. Enable either GENERATE_KEYS_ATSHA204A or GENERATE_KEYS_SOFT |")); + Serial.println( + F("| This will generate keys for ATSHA204A or software signing. |")); + Serial.println( + F("| b. Execute the sketch. You will be guided through the steps below under |")); + Serial.println( + F("| WHAT TO DO NEXT? |")); + Serial.println( + F("| c. Copy the generated keys and replace the topmost definitions in this file. |")); + Serial.println( + F("| d. Save the sketch and then disable the flag you just enabled. |")); + Serial.println( + F("| e. Enable PERSONALIZE_ATSHA204A to personalize the ATSHA204A device. |")); + Serial.println( + F("| or |")); + Serial.println( + F("| Enable PERSONALIZE_SOFT to personalize the EEPROM for software signing. |")); + Serial.println( + F("| If you want to use whitelisting you need to pick a unique serial number |")); + Serial.println( + F("| for each device you run the sketch on and fill in MY_SOFT_SERIAL. |")); + Serial.println( + F("| or |")); + Serial.println( + F("| Enable PERSONALIZE_SOFT_RANDOM_SERIAL to personalzie the EEPROM and |")); + Serial.println( + F("| include a new random serial number every time the sketch is executed. |")); + Serial.println( + F("| Take note of each saved serial number if you plan to use whitelisting. |")); + Serial.println( + F("| f. Execute the sketch on each device you want to personalize that is supposed |")); + Serial.println( + F("| to communicate securely. |")); + Serial.println( + F("| |")); + Serial.println( + F("| 2. Enable any configuration flag as you see fit. |")); + Serial.println( + F("| It is assumed that you know what you are doing. |")); + Serial.println( + F("+------------------------------------------------------------------------------------+")); + Serial.println(); +#else + Serial.println( + F("+------------------------------------------------------------------------------------+")); + Serial.println( + F("| Configuration settings |")); + Serial.println( + F("+------------------------------------------------------------------------------------+")); +#if defined(GENERATE_KEYS_ATSHA204A) + Serial.println( + F("| * Guided key generation for ATSHA204A using ATSHA024A |")); +#endif +#if defined(GENERATE_KEYS_SOFT) + Serial.println( + F("| * Guided key generation for EEPROM using software |")); +#endif +#if defined(PERSONALIZE_ATSHA204A) + Serial.println( + F("| * Guided personalization/storage of keys in ATSHA204A |")); +#endif +#if defined(PERSONALIZE_SOFT) + Serial.println( + F("| * Guided personalization/storage of keys in EEPROM |")); +#endif +#if defined(PERSONALIZE_SOFT_RANDOM_SERIAL) + Serial.println( + F("| * Guided storage and generation of random serial in EEPROM |")); +#endif +#if defined(USE_SOFT_SIGNING) + Serial.println( + F("| * Software based personalization (no ATSHA204A usage whatsoever) |")); +#else + Serial.println( + F("| * ATSHA204A based personalization |")); +#endif +#if defined(LOCK_ATSHA204A_CONFIGURATION) + Serial.println( + F("| * Will lock ATSHA204A configuration |")); +#endif +#if defined(SKIP_UART_CONFIRMATION) + Serial.println( + F("| * Will not require any UART confirmations |")); +#endif +#if defined(GENERATE_HMAC_KEY) + Serial.print( + F("| * Will generate HMAC key using ")); +#if defined(USE_SOFT_SIGNING) + Serial.println( + F("software |")); +#else + Serial.println( + F("ATSHA204A |")); +#endif +#endif +#if defined(STORE_HMAC_KEY) + Serial.print(F("| * Will store HMAC key to ")); +#if defined(USE_SOFT_SIGNING) + Serial.println( + F("EEPROM |")); +#else + Serial.println( + F("ATSHA204A |")); +#endif +#endif +#if defined(GENERATE_AES_KEY) + Serial.print( + F("| * Will generate AES key using ")); +#if defined(USE_SOFT_SIGNING) + Serial.println( + F("software |")); +#else + Serial.println( + F("ATSHA204A |")); +#endif +#endif +#if defined(STORE_AES_KEY) + Serial.println( + F("| * Will store AES key to EEPROM |")); +#endif +#if defined(GENERATE_SOFT_SERIAL) + Serial.println( + F("| * Will generate soft serial using software |")); +#endif +#if defined(STORE_SOFT_SERIAL) + Serial.println( + F("| * Will store soft serial to EEPROM |")); +#endif +#if defined(PRINT_DETAILED_ATSHA204A_CONFIG) + Serial.println( + F("| * Will print detailed ATSHA204A configuration |")); +#endif +#if defined(RESET_EEPROM_PERSONALIZATION) + Serial.println( + F("| * Will reset EEPROM personalization data |")); +#endif + Serial.println( + F("+------------------------------------------------------------------------------------+")); + Serial.println(); +#endif // not NO_SETTINGS_DEFINED + probe_and_print_peripherals(); +} + +static void print_ending(void) +{ +#if defined(GUIDED_MODE) || defined(NO_SETTINGS_DEFINED) + Serial.println( + F("+------------------------------------------------------------------------------------+")); + Serial.println( + F("| WHAT TO DO NEXT? |")); + Serial.println( + F("+------------------------------------------------------------------------------------+")); +#ifdef NO_SETTINGS_DEFINED + Serial.println( + F("| To proceed with the personalization, enable GENERATE_KEYS_ATSHA204A or |")); + Serial.println( + F("| GENERATE_KEYS_SOFT depending on what type of signing backend you plan to use. |")); + Serial.println( + F("| Both options will generate an AES key for encryption if you plan to use that. |")); + Serial.println( + F("| Recompile, upload and run the sketch again for further instructions. |")); + Serial.println( + F("+------------------------------------------------------------------------------------+")); +#endif +#ifdef GENERATE_KEYS_ATSHA204A + Serial.println( + F("| To proceed with the personalization, copy the keys shown in the Key copy section, |")); + Serial.println( + F("| and replace the corresponding definitions in the top of the sketch, then disable |")); + Serial.println( + F("| GENERATE_KEYS_ATSHA204A and enable PERSONALIZE_ATSHA204A. |")); + Serial.println( + F("+------------------------------------------------------------------------------------+")); +#endif +#ifdef GENERATE_KEYS_SOFT + Serial.println( + F("| To proceed with the personalization, copy the keys shown in the Key copy section, |")); + Serial.println( + F("| and replace the corresponding definitions in the top of the sketch, then disable |")); + Serial.println( + F("| GENERATE_KEYS_SOFT and enable PERSONALIZE_SOFT or PERSONALIZE_SOFT_RANDOM_SERIAL. |")); + Serial.println( + F("+------------------------------------------------------------------------------------+")); +#endif +#if defined(PERSONALIZE_ATSHA204A) ||\ + defined(PERSONALIZE_SOFT) ||\ + defined(PERSONALIZE_SOFT_RANDOM_SERIAL) + Serial.println( + F("| This device has now been personalized. Run this sketch with its current settings |")); + Serial.println( + F("| on all the devices in your network that have security enabled. |")); + Serial.println( + F("+------------------------------------------------------------------------------------+")); +#endif +#endif // GUIDED_MODE or NO_SETTINGS_DEFINED +} + +static void probe_and_print_peripherals(void) +{ + unique_id_t uniqueID; + + Serial.println( + F("+------------------------------------------------------------------------------------+")); + Serial.println( + F("| Hardware security peripherals |")); + Serial.println( + F("+--------------+--------------+--------------+------------------------------+--------+")); + Serial.println( + F("| Device | Status | Revision | Serial number | Locked |")); + Serial.println( + F("+--------------+--------------+--------------+------------------------------+--------+")); +#if defined(ARDUINO_ARCH_AVR) + Serial.print(F("| AVR | DETECTED | N/A | ")); +#elif defined(ARDUINO_ARCH_ESP8266) + Serial.print(F("| ESP8266 | DETECTED | N/A | ")); +#elif defined(ARDUINO_ARCH_SAMD) + Serial.print(F("| SAMD | DETECTED | N/A | ")); +#elif defined(ARDUINO_ARCH_STM32F1) + Serial.print(F("| STM32F1 | DETECTED | N/A | ")); +#elif defined(__linux__) + Serial.print(F("| Linux | DETECTED | N/A | ")); +#else + Serial.print(F("| Unknown | DETECTED | N/A | ")); +#endif + if (hwUniqueID(&uniqueID)) { + has_device_unique_id = true; + print_hex_buffer(uniqueID, 9); + Serial.println(F(" | N/A |")); + } else { + Serial.println(F("N/A (generation required) | N/A |")); + } + Serial.println( + F("+--------------+--------------+--------------+------------------------------+--------+")); +#ifndef USE_SOFT_SIGNING + Serial.print(F("| ATSHA204A | ")); + ret_code = sha204.sha204c_wakeup(rx_buffer); + if (ret_code != SHA204_SUCCESS) { + ret_code = SHA204_SUCCESS; // Reset retcode to avoid false negative execution result + Serial.println(F("NOT DETECTED | N/A | N/A | N/A |")); + } else { + uint8_t buffer[9]; + Serial.print(F("DETECTED | ")); + ret_code = sha204.sha204m_dev_rev(tx_buffer, rx_buffer); + if (ret_code != SHA204_SUCCESS) { + Serial.print(F("FAILED | ")); + } else { + print_hex_buffer(&rx_buffer[SHA204_BUFFER_POS_DATA], 4); + Serial.print(F(" | ")); + } + if (!get_atsha204a_serial(buffer)) { + memset(buffer, 0xFF, 9); + Serial.print(F("FAILED | ")); + } else { + print_hex_buffer(buffer, 9); + Serial.print(F(" | ")); + } + ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, 0x15<<2); + if (ret_code != SHA204_SUCCESS) { + Serial.println("FAILED |"); + } else { + if (rx_buffer[SHA204_BUFFER_POS_DATA+3] == 0x00) { + Serial.println("YES |"); + } else { + Serial.println("NO |"); + } + } + } + Serial.println( + F("+--------------+--------------+--------------+------------------------------+--------+")); +#ifdef PRINT_DETAILED_ATSHA204A_CONFIG + Serial.println( + F("+------------------------------------------------------------------------------------+")); + Serial.println( + F("| Current ATSHA204A Configuration |")); + dump_detailed_atsha204a_configuration(); +#endif +#endif // not USE_SOFT_SIGNING + Serial.println(); +} + +static void print_eeprom_data(void) { uint8_t buffer[32]; -#ifndef USE_SOFT_SIGNING - Serial.println(F("EEPROM DATA:")); -#endif + + Serial.println( + F("+------------------------------------------------------------------------------------+")); + Serial.println( + F("| EEPROM |")); + Serial.println( + F("+--------+--------+------------------------------------------------------------------+")); + Serial.println( + F("| Key ID | Status | Key |")); + Serial.println( + F("+--------+--------+------------------------------------------------------------------+")); + Serial.print(F("| HMAC | ")); 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); + if (!memcmp(buffer, reset_buffer, 32)) { + Serial.print(F("RESET | ")); + } else { + Serial.print(F("OK | ")); } - 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(); + print_hex_buffer(buffer, 32); + Serial.println(F(" |")); + Serial.print(F("| AES | ")); 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); + if (!memcmp(buffer, reset_buffer, 16)) { + Serial.print(F("RESET | ")); + } else { + Serial.print(F("OK | ")); } + print_hex_buffer(buffer, 16); + Serial.println(F(" |")); + Serial.print(F("| SERIAL | ")); + hwReadConfigBlock((void*)buffer, (void*)EEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9); + if (!memcmp(buffer, reset_buffer, 9)) { + if (has_device_unique_id) { + Serial.println(F("N/A | Device unique serial, not stored in EEPROM |")); + } else { + Serial.print(F("RESET | ")); + print_hex_buffer(buffer, 9); + Serial.println(F(" |")); + } + } else { + Serial.print(F("OK | ")); + print_hex_buffer(buffer, 9); + Serial.println(F(" |")); + } + Serial.println( + F("+--------+--------+------------------------------------------------------------------+")); 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:")); +} + +static void print_whitelisting_entry(void) +{ + uint8_t buffer[9]; +#ifdef USE_SOFT_SIGNING + unique_id_t uniqueID; + hwReadConfigBlock((void*)buffer, (void*)EEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9); + if (!memcmp(buffer, reset_buffer, 9)) { + // Serial reset in EEPROM, check for unique ID + if (hwUniqueID(&uniqueID)) { + memcpy(buffer, uniqueID, 9); + } + } +#else + // If ATSHA204A is used, use that serial here + if (!get_atsha204a_serial(buffer)) { + memset(buffer, 0xFF, 9); + } +#endif + Serial.println( + F("+------------------------------------------------------------------------------------+")); + Serial.println( + F("| This nodes whitelist entry on other nodes |")); + Serial.println( + F("+------------------------------------------------------------------------------------+")); + Serial.print(F("{.nodeId = ,.serial = {")); + print_c_friendly_hex_buffer(buffer, 9); + Serial.println(F("}}")); + Serial.println( + F("+------------------------------------------------------------------------------------+")); +} + +#ifdef PRINT_DETAILED_ATSHA204A_CONFIG +/** @brief Dump current configuration to UART */ +static void dump_detailed_atsha204a_configuration(void) +{ + Serial.println( + F("+---------------------------------------------------------------++-------------------+")); + Serial.println( + F("| Fieldname || Data |")); + Serial.println( + F("+-------------------------------+-------------------------------++---------+---------+")); for (int i=0; i < 88; i += 4) { ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, i); if (ret_code != SHA204_SUCCESS) { - Serial.print(F("Failed to read config. Response: ")); - Serial.println(ret_code, HEX); - halt(); + Serial.println( + F("+------------------------------------------------------------------------------------+")); + halt(false); } if (i == 0x00) { - Serial.print(F(" SN[0:1] | SN[2:3] | ")); + Serial.print(F("| SN[0:1] | SN[2:3] || ")); for (int j=0; j<4; j++) { if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { Serial.print('0'); // Because Serial.print does not 0-pad HEX @@ -413,33 +1512,43 @@ void dump_configuration() Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); if (j == 1) { Serial.print(F(" | ")); - } else { + } else if (j < 3) { Serial.print(F(" ")); } } - Serial.println(); + Serial.println(F(" |")); + Serial.println( + F("+-------------------------------+-------------------------------++---------+---------+")); } else if (i == 0x04) { - Serial.print(F(" Revnum | ")); + Serial.print(F("| Revnum || ")); for (int j=0; j<4; j++) { if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { Serial.print('0'); // Because Serial.print does not 0-pad HEX } Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - Serial.print(F(" ")); + if (j < 3) { + Serial.print(F(" ")); + } } - Serial.println(); + Serial.println(F(" |")); + Serial.println( + F("+---------------------------------------------------------------++-------------------+")); } else if (i == 0x08) { - Serial.print(F(" SN[4:7] | ")); + Serial.print(F("| SN[4:7] || ")); for (int j=0; j<4; j++) { if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { Serial.print('0'); // Because Serial.print does not 0-pad HEX } Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - Serial.print(F(" ")); + if (j < 3) { + Serial.print(F(" ")); + } } - Serial.println(); + Serial.println(F(" |")); + Serial.println( + F("+---------------+---------------+---------------+---------------++----+----+----+----+")); } else if (i == 0x0C) { - Serial.print(F(" SN[8] | Reserved13 | I2CEnable | Reserved15 | ")); + Serial.print(F("| SN[8] | Reserved13 | I2CEnable | Reserved15 || ")); for (int j=0; j<4; j++) { if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { Serial.print('0'); // Because Serial.print does not 0-pad HEX @@ -448,12 +1557,13 @@ void dump_configuration() if (j < 3) { Serial.print(F(" | ")); } else { - Serial.print(F(" ")); + Serial.println(F(" |")); } } - Serial.println(); + Serial.println( + F("+---------------+---------------+---------------+---------------++----+----+----+----+")); } else if (i == 0x10) { - Serial.print(F(" I2CAddress | TempOffset | OTPmode | SelectorMode | ")); + Serial.print(F("| I2CAddress | TempOffset | OTPmode | SelectorMode || ")); for (int j=0; j<4; j++) { if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { Serial.print('0'); // Because Serial.print does not 0-pad HEX @@ -462,12 +1572,13 @@ void dump_configuration() if (j < 3) { Serial.print(F(" | ")); } else { - Serial.print(F(" ")); + Serial.println(F(" |")); } } - Serial.println(); + Serial.println( + F("+---------------+---------------+---------------+---------------++----+----+----+----+")); } else if (i == 0x14) { - Serial.print(F(" SlotConfig00 | SlotConfig01 | ")); + Serial.print(F("| SlotConfig00 | SlotConfig01 || ")); for (int j=0; j<4; j++) { if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { Serial.print('0'); // Because Serial.print does not 0-pad HEX @@ -475,13 +1586,15 @@ void dump_configuration() Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); if (j == 1) { Serial.print(F(" | ")); - } else { + } else if (j < 3) { Serial.print(F(" ")); } } - Serial.println(); + Serial.println(F(" |")); + Serial.println( + F("+-------------------------------+-------------------------------++---------+---------+")); } else if (i == 0x18) { - Serial.print(F(" SlotConfig02 | SlotConfig03 | ")); + Serial.print(F("| SlotConfig02 | SlotConfig03 || ")); for (int j=0; j<4; j++) { if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { Serial.print('0'); // Because Serial.print does not 0-pad HEX @@ -489,13 +1602,15 @@ void dump_configuration() Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); if (j == 1) { Serial.print(F(" | ")); - } else { + } else if (j < 3) { Serial.print(F(" ")); } } - Serial.println(); + Serial.println(F(" |")); + Serial.println( + F("+-------------------------------+-------------------------------++---------+---------+")); } else if (i == 0x1C) { - Serial.print(F(" SlotConfig04 | SlotConfig05 | ")); + Serial.print(F("| SlotConfig04 | SlotConfig05 || ")); for (int j=0; j<4; j++) { if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { Serial.print('0'); // Because Serial.print does not 0-pad HEX @@ -503,13 +1618,15 @@ void dump_configuration() Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); if (j == 1) { Serial.print(F(" | ")); - } else { + } else if (j < 3) { Serial.print(F(" ")); } } - Serial.println(); + Serial.println(F(" |")); + Serial.println( + F("+-------------------------------+-------------------------------++---------+---------+")); } else if (i == 0x20) { - Serial.print(F(" SlotConfig06 | SlotConfig07 | ")); + Serial.print(F("| SlotConfig06 | SlotConfig07 || ")); for (int j=0; j<4; j++) { if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { Serial.print('0'); // Because Serial.print does not 0-pad HEX @@ -517,13 +1634,15 @@ void dump_configuration() Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); if (j == 1) { Serial.print(F(" | ")); - } else { + } else if (j < 3) { Serial.print(F(" ")); } } - Serial.println(); + Serial.println(F(" |")); + Serial.println( + F("+-------------------------------+-------------------------------++---------+---------+")); } else if (i == 0x24) { - Serial.print(F(" SlotConfig08 | SlotConfig09 | ")); + Serial.print(F("| SlotConfig08 | SlotConfig09 || ")); for (int j=0; j<4; j++) { if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { Serial.print('0'); // Because Serial.print does not 0-pad HEX @@ -531,13 +1650,15 @@ void dump_configuration() Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); if (j == 1) { Serial.print(F(" | ")); - } else { + } else if (j < 3) { Serial.print(F(" ")); } } - Serial.println(); + Serial.println(F(" |")); + Serial.println( + F("+-------------------------------+-------------------------------++---------+---------+")); } else if (i == 0x28) { - Serial.print(F(" SlotConfig0A | SlotConfig0B | ")); + Serial.print(F("| SlotConfig0A | SlotConfig0B || ")); for (int j=0; j<4; j++) { if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { Serial.print('0'); // Because Serial.print does not 0-pad HEX @@ -545,13 +1666,15 @@ void dump_configuration() Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); if (j == 1) { Serial.print(F(" | ")); - } else { + } else if (j < 3) { Serial.print(F(" ")); } } - Serial.println(); + Serial.println(F(" |")); + Serial.println( + F("+-------------------------------+-------------------------------++---------+---------+")); } else if (i == 0x2C) { - Serial.print(F(" SlotConfig0C | SlotConfig0D | ")); + Serial.print(F("| SlotConfig0C | SlotConfig0D || ")); for (int j=0; j<4; j++) { if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { Serial.print('0'); // Because Serial.print does not 0-pad HEX @@ -559,13 +1682,15 @@ void dump_configuration() Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); if (j == 1) { Serial.print(F(" | ")); - } else { + } else if (j < 3) { Serial.print(F(" ")); } } - Serial.println(); + Serial.println(F(" |")); + Serial.println( + F("+-------------------------------+-------------------------------++---------+---------+")); } else if (i == 0x30) { - Serial.print(F(" SlotConfig0E | SlotConfig0F | ")); + Serial.print(F("| SlotConfig0E | SlotConfig0F || ")); for (int j=0; j<4; j++) { if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { Serial.print('0'); // Because Serial.print does not 0-pad HEX @@ -573,13 +1698,15 @@ void dump_configuration() Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); if (j == 1) { Serial.print(F(" | ")); - } else { + } else if (j < 3) { Serial.print(F(" ")); } } - Serial.println(); + Serial.println(F(" |")); + Serial.println( + F("+---------------+---------------+---------------+---------------++----+----+----+----+")); } else if (i == 0x34) { - Serial.print(F(" UseFlag00 | UpdateCount00 | UseFlag01 | UpdateCount01 | ")); + Serial.print(F("| UseFlag00 | UpdateCount00 | UseFlag01 | UpdateCount01 || ")); for (int j=0; j<4; j++) { if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { Serial.print('0'); // Because Serial.print does not 0-pad HEX @@ -588,12 +1715,13 @@ void dump_configuration() if (j < 3) { Serial.print(F(" | ")); } else { - Serial.print(F(" ")); + Serial.println(F(" |")); } } - Serial.println(); + Serial.println( + F("+---------------+---------------+---------------+---------------++----+----+----+----+")); } else if (i == 0x38) { - Serial.print(F(" UseFlag02 | UpdateCount02 | UseFlag03 | UpdateCount03 | ")); + Serial.print(F("| UseFlag02 | UpdateCount02 | UseFlag03 | UpdateCount03 || ")); for (int j=0; j<4; j++) { if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { Serial.print('0'); // Because Serial.print does not 0-pad HEX @@ -602,12 +1730,13 @@ void dump_configuration() if (j < 3) { Serial.print(F(" | ")); } else { - Serial.print(F(" ")); + Serial.println(F(" |")); } } - Serial.println(); + Serial.println( + F("+---------------+---------------+---------------+---------------++----+----+----+----+")); } else if (i == 0x3C) { - Serial.print(F(" UseFlag04 | UpdateCount04 | UseFlag05 | UpdateCount05 | ")); + Serial.print(F("| UseFlag04 | UpdateCount04 | UseFlag05 | UpdateCount05 || ")); for (int j=0; j<4; j++) { if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { Serial.print('0'); // Because Serial.print does not 0-pad HEX @@ -616,12 +1745,13 @@ void dump_configuration() if (j < 3) { Serial.print(F(" | ")); } else { - Serial.print(F(" ")); + Serial.println(F(" |")); } } - Serial.println(); + Serial.println( + F("+---------------+---------------+---------------+---------------++----+----+----+----+")); } else if (i == 0x40) { - Serial.print(F(" UseFlag06 | UpdateCount06 | UseFlag07 | UpdateCount07 | ")); + Serial.print(F("| UseFlag06 | UpdateCount06 | UseFlag07 | UpdateCount07 || ")); for (int j=0; j<4; j++) { if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { Serial.print('0'); // Because Serial.print does not 0-pad HEX @@ -630,52 +1760,69 @@ void dump_configuration() if (j < 3) { Serial.print(F(" | ")); } else { - Serial.print(F(" ")); + Serial.println(F(" |")); } } - Serial.println(); + Serial.println( + F("+---------------+---------------+---------------+---------------++----+----+----+----+")); } else if (i == 0x44) { - Serial.print(F(" LastKeyUse[0:3] | ")); + Serial.print(F("| LastKeyUse[0:3] || ")); for (int j=0; j<4; j++) { if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { Serial.print('0'); // Because Serial.print does not 0-pad HEX } Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - Serial.print(F(" ")); + if (j < 3) { + Serial.print(F(" ")); + } } - Serial.println(); + Serial.println(F(" |")); + Serial.println( + F("+---------------------------------------------------------------++-------------------+")); } else if (i == 0x48) { - Serial.print(F(" LastKeyUse[4:7] | ")); + Serial.print(F("| LastKeyUse[4:7] || ")); for (int j=0; j<4; j++) { if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { Serial.print('0'); // Because Serial.print does not 0-pad HEX } Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - Serial.print(F(" ")); + if (j < 3) { + Serial.print(F(" ")); + } } - Serial.println(); + Serial.println(F(" |")); + Serial.println( + F("+---------------------------------------------------------------++-------------------+")); } else if (i == 0x4C) { - Serial.print(F(" LastKeyUse[8:B] | ")); + Serial.print(F("| LastKeyUse[8:B] || ")); for (int j=0; j<4; j++) { if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { Serial.print('0'); // Because Serial.print does not 0-pad HEX } Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - Serial.print(F(" ")); + if (j < 3) { + Serial.print(F(" ")); + } } - Serial.println(); + Serial.println(F(" |")); + Serial.println( + F("+---------------------------------------------------------------++-------------------+")); } else if (i == 0x50) { - Serial.print(F(" LastKeyUse[C:F] | ")); + Serial.print(F("| LastKeyUse[C:F] || ")); for (int j=0; j<4; j++) { if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { Serial.print('0'); // Because Serial.print does not 0-pad HEX } Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - Serial.print(F(" ")); + if (j < 3) { + Serial.print(F(" ")); + } } - Serial.println(); + Serial.println(F(" |")); + Serial.println( + F("+---------------+---------------+---------------+---------------++----+----+----+----+")); } else if (i == 0x54) { - Serial.print(F(" UserExtra | Selector | LockValue | LockConfig | ")); + Serial.print(F("| UserExtra | Selector | LockValue | LockConfig || ")); for (int j=0; j<4; j++) { if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { Serial.print('0'); // Because Serial.print does not 0-pad HEX @@ -684,454 +1831,33 @@ void dump_configuration() if (j < 3) { Serial.print(F(" | ")); } else { - Serial.print(F(" ")); + Serial.println(F(" |")); } } - Serial.println(); + Serial.println( + F("+---------------+---------------+---------------+---------------++----+----+----+----+")); } } -#endif // not USE_SOFT_SIGNING } +#endif // PRINT_DETAILED_ATSHA204A_CONFIG -/** @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 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)); +// Doxygen specific constructs, not included when built normally +// This is used to enable disabled macros/definitions to be included in the documentation as well. +#if DOXYGEN +#define GENERATE_KEYS_ATSHA204A +#define GENERATE_KEYS_SOFT +#define PERSONALIZE_ATSHA204A +#define PERSONALIZE_SOFT +#define PERSONALIZE_SOFT_RANDOM_SERIAL +#define USE_SOFT_SIGNING +#define LOCK_ATSHA204A_CONFIGURATION +#define SKIP_UART_CONFIRMATION +#define GENERATE_HMAC_KEY +#define STORE_HMAC_KEY +#define GENERATE_AES_KEY +#define STORE_AES_KEY +#define GENERATE_SOFT_SERIAL +#define STORE_SOFT_SERIAL +#define PRINT_DETAILED_ATSHA204A_CONFIG +#define RESET_EEPROM_PERSONALIZATION #endif - uint8_t key[32]; - (void)key; - - Serial.begin(115200); - hwInit(); - 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) { - 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) { - Serial.print(F("Failed to determine device revision. Response: ")); - Serial.println(ret_code, HEX); - halt(); - } else { - Serial.print(F("Device revision: ")); - for (int i=0; i<4; i++) { - if (rx_buffer[SHA204_BUFFER_POS_DATA+i] < 0x10) { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+i], HEX); - } - Serial.println(); - } - - // Output serial number on console - ret_code = sha204.getSerialNumber(rx_buffer); - if (ret_code != SHA204_SUCCESS) { - Serial.print(F("Failed to obtain device serial number. Response: ")); - Serial.println(ret_code, HEX); - halt(); - } else { - Serial.print(F("Device serial: ")); - Serial.print('{'); - for (int i=0; i<9; i++) { - Serial.print(F("0x")); - if (rx_buffer[i] < 0x10) { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[i], HEX); - if (i < 8) { - Serial.print(','); - } - } - Serial.print('}'); - Serial.println(); - for (int i=0; i<9; i++) { - if (rx_buffer[i] < 0x10) { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[i], HEX); - } - Serial.println(); - } - - if (lockConfig != 0x00) { - // Write config and get CRC for the updated config - crc = write_config_and_get_crc(); - - // List current configuration before attempting to lock - Serial.println(F("Chip configuration:")); - dump_configuration(); - -#ifdef LOCK_CONFIGURATION - // Purge serial input buffer -#ifndef SKIP_UART_CONFIRMATION - while (Serial.available()) { - Serial.read(); - } - Serial.println(F("Send SPACE character now to lock the configuration...")); - - while (Serial.available() == 0); - if (Serial.read() == ' ') -#endif //not SKIP_UART_CONFIRMATION - { - Serial.println(F("Locking configuration...")); - - // Correct sequence, resync chip - ret_code = sha204.sha204c_resync(SHA204_RSP_SIZE_MAX, rx_buffer); - if (ret_code != SHA204_SUCCESS && ret_code != SHA204_RESYNC_WITH_WAKEUP) { - Serial.print(F("Resync failed. Response: ")); - Serial.println(ret_code, HEX); - halt(); - } - - // Lock configuration zone - ret_code = sha204.sha204m_execute(SHA204_LOCK, SHA204_ZONE_CONFIG, - crc, 0, NULL, 0, NULL, 0, NULL, - LOCK_COUNT, tx_buffer, LOCK_RSP_SIZE, rx_buffer); - if (ret_code != SHA204_SUCCESS) { - Serial.print(F("Configuration lock failed. Response: ")); - Serial.println(ret_code, HEX); - halt(); - } else { - Serial.println(F("Configuration locked.")); - - // Update lock flags after locking - 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]; - } - } - } -#ifndef SKIP_UART_CONFIRMATION - else { - Serial.println(F("Unexpected answer. Skipping lock.")); - } -#endif //not SKIP_UART_CONFIRMATION -#else //LOCK_CONFIGURATION - Serial.println(F("Configuration not locked. Define LOCK_CONFIGURATION to lock for real.")); -#endif - } else { - Serial.println(F("Skipping configuration write and lock (configuration already locked).")); - Serial.println(F("Chip configuration:")); - dump_configuration(); - } - -#ifdef SKIP_KEY_STORAGE - Serial.println(F("Disable SKIP_KEY_STORAGE to store key.")); -#else -#ifdef USER_KEY - memcpy(key, user_key_data, 32); - 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); - 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("Take note of this key, it will never be the shown again:")); - } else { - Serial.println(F("Key is not randomized (configuration not locked):")); - } -#endif - Serial.print("#define MY_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(','); - } - if (i+1 == 16) { - Serial.print("\\\n "); - } - } - Serial.println(); - - // It will not be possible to write the key if the configuration zone is unlocked - if (lockConfig == 0x00) { - // Write the key to the appropriate slot in the data zone - Serial.println(F("Writing key to slot 0...")); - write_key(key); - } else { - Serial.println(F("Skipping key storage (configuration not locked).")); - Serial.println(F("The configuration must be locked to be able to write a key.")); - } -#endif - - if (lockValue != 0x00) { -#ifdef LOCK_DATA -#ifndef SKIP_UART_CONFIRMATION - while (Serial.available()) { - Serial.read(); - } - Serial.println(F("Send SPACE character to lock data...")); - while (Serial.available() == 0); - if (Serial.read() == ' ') -#endif //not SKIP_UART_CONFIRMATION - { - // Correct sequence, resync chip - ret_code = sha204.sha204c_resync(SHA204_RSP_SIZE_MAX, rx_buffer); - if (ret_code != SHA204_SUCCESS && ret_code != SHA204_RESYNC_WITH_WAKEUP) { - Serial.print(F("Resync failed. Response: ")); - Serial.println(ret_code, HEX); - halt(); - } - - // If configuration is unlocked, key is not updated. Locking data in this case will cause - // slot 0 to contain an unknown (or factory default) key, and this is in practically any - // usecase not the desired behaviour, so ask for additional confirmation in this case. - if (lockConfig != 0x00) { - while (Serial.available()) { - Serial.read(); - } - Serial.println(F("*** ATTENTION ***")); - Serial.println(F("Configuration is not locked. Are you ABSULOUTELY SURE you want to lock data?")); - Serial.println(F("Locking data at this stage will cause slot 0 to contain a factory default key")); - Serial.println( - F("which cannot be change after locking is done. This is in practically any usecase")); - Serial.println(F("NOT the desired behavour. Send SPACE character now to lock data anyway...")); - while (Serial.available() == 0); - if (Serial.read() != ' ') { - Serial.println(F("Unexpected answer. Skipping lock.")); - halt(); - } - } - - // Lock data zone - ret_code = sha204.sha204m_execute(SHA204_LOCK, SHA204_ZONE_DATA | LOCK_ZONE_NO_CRC, - 0x0000, 0, NULL, 0, NULL, 0, NULL, - LOCK_COUNT, tx_buffer, LOCK_RSP_SIZE, rx_buffer); - if (ret_code != SHA204_SUCCESS) { - Serial.print(F("Data lock failed. Response: ")); - Serial.println(ret_code, HEX); - halt(); - } else { - Serial.println(F("Data locked.")); - - // Update lock flags after locking - 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]; - } - } - } -#ifndef SKIP_UART_CONFIRMATION - else { - Serial.println(F("Unexpected answer. Skipping lock.")); - } -#endif //not SKIP_UART_CONFIRMATION -#else //LOCK_DATA - Serial.println(F("Data not locked. Define LOCK_DATA to lock for real.")); -#endif - } else { - 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) { - Serial.println("LOCKED"); - } else { - Serial.println("UNLOCKED"); - } - Serial.print(F("Data is ")); - if (lockValue == 0x00) { - Serial.println("LOCKED"); - } else { - Serial.println("UNLOCKED"); - } -#endif -} - -/** @brief Sketch execution code */ -void loop() -{ -} diff --git a/projects/SublimeText/MySensors.sublime-project b/projects/SublimeText/MySensors.sublime-project index a1c544a..9891739 100644 --- a/projects/SublimeText/MySensors.sublime-project +++ b/projects/SublimeText/MySensors.sublime-project @@ -41,6 +41,7 @@ "use_only_additional_options": true }, }, + "rulers": [100], }, // MySensors core library uses cppcheck to do static code analysis. // The below settings enable cppcheck as a linter for automatic code analysis during development.