Completed OTA logic

OTA pasword now stored in NVS.  Use 'O' command to change from default.  Note password is stored as MD5 hash, and is therefore unrecoverable.  Changes to password DO NOT take effect until next reboot.  Password CAN be changed even if OTA has not been enabled for sketch.  Blank passwords are not allowed.

Stored password can only be erased with 'E' command.
This commit is contained in:
Gregg 2021-02-07 09:58:52 -06:00
parent 208905419c
commit 29470e4dd9
5 changed files with 51 additions and 7 deletions

View File

@ -28,6 +28,7 @@
#include <ESPmDNS.h>
#include <nvs_flash.h>
#include <sodium.h>
#include <MD5Builder.h>
#include "HAP.h"
#include "HomeSpan.h"
@ -43,10 +44,21 @@ void HAPClient::init(){
nvs_open("WIFI",NVS_READWRITE,&wifiNVS); // open WIFI data namespace in NVS
nvs_open("SRP",NVS_READWRITE,&srpNVS); // open SRP data namespace in NVS
nvs_open("HAP",NVS_READWRITE,&hapNVS); // open HAP data namespace in NVS
nvs_open("OTA",NVS_READWRITE,&otaNVS); // open OTA data namespace in NVS
if(!nvs_get_blob(wifiNVS,"WIFIDATA",NULL,&len)) // if found WiFi data in NVS
nvs_get_blob(wifiNVS,"WIFIDATA",&homeSpan.network.wifiData,&len); // retrieve data
if(!nvs_get_str(otaNVS,"OTADATA",NULL,&len)){ // if found OTA data in NVS
nvs_get_str(otaNVS,"OTADATA",homeSpan.otaPwd,&len); // retrieve data
} else {
MD5Builder otaPwdHash;
otaPwdHash.begin();
otaPwdHash.add(DEFAULT_OTA_PASSWORD);
otaPwdHash.calculate();
otaPwdHash.getChars(homeSpan.otaPwd);
}
struct { // temporary structure to hold SRP verification code and salt stored in NVS
uint8_t salt[16];
uint8_t verifyCode[384];
@ -1643,6 +1655,7 @@ TLV<kTLVType,10> HAPClient::tlv8;
nvs_handle HAPClient::hapNVS;
nvs_handle HAPClient::wifiNVS;
nvs_handle HAPClient::srpNVS;
nvs_handle HAPClient::otaNVS;
uint8_t HAPClient::httpBuf[MAX_HTTP+1];
HKDF HAPClient::hkdf;
pairState HAPClient::pairStatus;

View File

@ -82,6 +82,7 @@ struct HAPClient {
static nvs_handle hapNVS; // handle for non-volatile-storage of HAP data
static nvs_handle wifiNVS; // handle for non-volatile-storage of WiFi data
static nvs_handle srpNVS; // handle for non-volatile-storage of SRP data
static nvs_handle otaNVS; // handle for non-volatile-storage of OTA data
static uint8_t httpBuf[MAX_HTTP+1]; // buffer to store HTTP messages (+1 to leave room for storing an extra 'overflow' character)
static HKDF hkdf; // generates (and stores) HKDF-SHA-512 32-byte keys derived from an inputKey of arbitrary length, a salt string, and an info string
static pairState pairStatus; // tracks pair-setup status

View File

@ -434,7 +434,8 @@ void Span::checkConnect(){
if(otaEnabled){
ArduinoOTA.setHostname(hostName);
ArduinoOTA.setPasswordHash(otaPwd);
ArduinoOTA
.onStart([]() {
String type;
@ -539,7 +540,7 @@ void Span::processSerialCommand(const char *c){
Serial.print("\n");
}
Serial.print("\n*** End Status ***\n");
Serial.print("\n*** End Status ***\n\n");
}
break;
@ -565,7 +566,7 @@ void Span::processSerialCommand(const char *c){
if(strlen(s)==4 && strlen(tBuf)==4){
sprintf(qrID,"%s",tBuf);
Serial.print("\n\nChanging default Setup ID for QR Code to : '");
Serial.print("\nChanging default Setup ID for QR Code to: '");
Serial.print(qrID);
Serial.print("'. Will take effect after next restart.\n\n");
nvs_set_str(HAPClient::hapNVS,"SETUPID",qrID); // update data
@ -578,6 +579,32 @@ void Span::processSerialCommand(const char *c){
}
break;
case 'O': {
char textPwd[33]="\0";
while(!strlen(textPwd)){
Serial.print("\n>>> OTA Password (32 characters max): ");
readSerial(textPwd,32);
Serial.print(mask(textPwd,2));
Serial.print("\n");
}
MD5Builder otaPwdHash;
otaPwdHash.begin();
otaPwdHash.add(textPwd);
otaPwdHash.calculate();
otaPwdHash.getChars(otaPwd);
nvs_set_str(HAPClient::otaNVS,"OTADATA",otaPwd); // update data
nvs_commit(HAPClient::otaNVS);
Serial.print("\nPassword change will take effect after next restart.\n");
if(!otaEnabled)
Serial.print("Note: OTA has not been enabled in this sketch.\n");
Serial.print("\n");
}
break;
case 'S': {
char buf[128];
@ -791,6 +818,7 @@ void Span::processSerialCommand(const char *c){
Serial.print(" X - delete WiFi Credentials and restart\n");
Serial.print(" S <code> - change the HomeKit Pairing Setup Code to <code>\n");
Serial.print(" Q <id> - change the HomeKit Setup ID for QR Codes to <id>\n");
Serial.print(" O - change the OTA password\n");
Serial.print(" A - start the HomeSpan Setup Access Point\n");
Serial.print("\n");
Serial.print(" U - unpair device by deleting all Controller data\n");

View File

@ -100,7 +100,8 @@ struct Span{
unsigned long comModeLife=DEFAULT_COMMAND_TIMEOUT*1000; // length of time (in milliseconds) to keep Command Mode alive before resuming normal operations
uint16_t tcpPortNum=DEFAULT_TCP_PORT; // port for TCP communications between HomeKit and HomeSpan
char qrID[5]=""; // Setup ID used for pairing with QR Code
boolean otaEnabled=false; // enables Over-the-Air updates
boolean otaEnabled=false; // enables Over-the-Air ("OTA") updates
char otaPwd[33]; // MD5 Hash of OTA password, represented as a string of hexidecimal characters
WiFiServer *hapServer; // pointer to the HAP Server connection
Blinker statusLED; // indicates HomeSpan status

View File

@ -66,8 +66,9 @@
#define DEFAULT_CONTROL_PIN 21 // change with homeSpan.setControlPin(pin)
#define DEFAULT_STATUS_PIN 13 // change with homeSpan.setStatusPin(pin)
#define DEFAULT_AP_SSID "HomeSpan-Setup" // change with homeSpan.setApSSID(pwd)
#define DEFAULT_AP_SSID "HomeSpan-Setup" // change with homeSpan.setApSSID(ssid)
#define DEFAULT_AP_PASSWORD "homespan" // change with homeSpan.setApPassword(pwd)
#define DEFAULT_OTA_PASSWORD "homespan-ota" // change with 'O' command
#define DEFAULT_AP_TIMEOUT 300 // change with homeSpan.setApTimeout(nSeconds)
#define DEFAULT_COMMAND_TIMEOUT 120 // change with homeSpan.setCommandTimeout(nSeconds)
@ -87,7 +88,7 @@
#define LED_WIFI_CONNECTING 2000 // slow flashing
#define LED_AP_STARTED 100,0.5,2,300 // rapid double-blink
#define LED_AP_CONNECTED 300,0.5,2,400 // medium double-blink
#define LED_OTA_STARTED 300,0.5,5,500 // rapid 5-blink
#define LED_OTA_STARTED 300,0.5,3,400 // medium triple-blink
/////////////////////////////////////////////////////
// Message Log Level Control Macros //