From 1569019fab9dd308f7950f65739b314fc51b0d48 Mon Sep 17 00:00:00 2001 From: Michael Geramb Date: Sun, 12 Nov 2023 19:38:19 +0100 Subject: [PATCH] Add handling for updateDatabase() in call context --- ...ndEncryptedContext.cpp => CallContext.cpp} | 85 +++++++++++++------ src/{SendEncryptedContext.h => CallContext.h} | 58 ++++++++++--- src/HAP.cpp | 6 +- src/HomeSpan.cpp | 37 ++++---- src/HomeSpan.h | 4 +- 5 files changed, 128 insertions(+), 62 deletions(-) rename src/{SendEncryptedContext.cpp => CallContext.cpp} (74%) rename src/{SendEncryptedContext.h => CallContext.h} (56%) diff --git a/src/SendEncryptedContext.cpp b/src/CallContext.cpp similarity index 74% rename from src/SendEncryptedContext.cpp rename to src/CallContext.cpp index f57d8d9..1219f89 100644 --- a/src/SendEncryptedContext.cpp +++ b/src/CallContext.cpp @@ -26,23 +26,18 @@ ********************************************************************************/ #include -#include "SendEncryptedContext.h" +#include "CallContext.h" #include "HomeSpan.h" #include "HAP.h" #include "Settings.h" #include -SendEncryptedContext::SendEncryptedContext(HAPClient& hapClient) -: hapClient(hapClient), - stringBuffer(FRAME_SIZE + 1, "SendEncryptedContext dataBuffer"), - sendBuffer(FRAME_SIZE + 2 + 16, "SendEncryptedContext sendBuffer") // FRAME_SIZE + AAD + Auth +CallContext::CallContext() + : stringBuffer(1024, "CallContext stringBuffer") { - LOG2("\n>>>>>>>>>> "); - LOG2(hapClient.client.remoteIP()); - LOG2(" >>>>>>>>>>\n"); } -void SendEncryptedContext::printf(const char* format, ...) +void CallContext::printf(const char* format, ...) { va_list ap; va_start(ap, format); @@ -53,28 +48,19 @@ void SendEncryptedContext::printf(const char* format, ...) va_end(ap); } -void SendEncryptedContext::print(const char* text) -{ - auto len = strlen(text); - auto buffer = reserveStringBuffer(len); - memcpy(buffer, text, len); - LOG2(buffer); -} -char* SendEncryptedContext::reserveStringBuffer(int stringLength) +char* CallContext::reserveStringBuffer(int stringLength) { int requiredNewBufferLength = stringLength + 1; // reserve buffer for characters and string terminator '\0' if (stringBuffer.len() - usedStringLength < requiredNewBufferLength) { // to less memory, send first exitsting buffer if (usedStringLength > 0) - { - sendEncrypted(stringBuffer.get(), usedStringLength); - usedStringLength = 0; - } + flush(); + // Check if still more memory is needed if (stringBuffer.len() < requiredNewBufferLength) - stringBuffer = TempBuffer(requiredNewBufferLength, "SendEncryptedContext::reserveMemory"); + stringBuffer = TempBuffer(requiredNewBufferLength, "SendEncryptedCallContext::reserveMemory"); } int alreadyInUse = usedStringLength; usedStringLength += stringLength; @@ -83,11 +69,35 @@ char* SendEncryptedContext::reserveStringBuffer(int stringLength) return result; } -void SendEncryptedContext::sendEncrypted(const char* buffer, int length) +void CallContext::flush() +{ + handlePage(stringBuffer.get(), usedStringLength); + usedStringLength = 0; +} + +void CallContext::print(const char* text) +{ + auto len = strlen(text); + auto buffer = reserveStringBuffer(len); + memcpy(buffer, text, len); + LOG2(buffer); +} + +SendEncryptedCallContext::SendEncryptedCallContext(HAPClient& hapClient) +: hapClient(hapClient), + sendBuffer(FRAME_SIZE + 2 + 16, "SendEncryptedCallContext sendBuffer") // FRAME_SIZE + AAD + Auth +{ + LOG2("\n>>>>>>>>>> "); + LOG2(hapClient.client.remoteIP()); + LOG2(" >>>>>>>>>>\n"); +} + + + +void SendEncryptedCallContext::handlePage(const char* buffer, int length) { if (length == 0) return; - sentLength += length; LOG2(buffer); for(int i=0;i 0) - sendEncrypted(stringBuffer.get(), usedStringLength); + flush(); LOG2("-------- SENT ENCRYPTED! --------\n"); } + + +CalcHashCallContext::CalcHashCallContext() +: CallContext() +{ + memset(&tHash, 0, HASH_SIZE); +} + +void CalcHashCallContext::handlePage(const char* buffer, int length) +{ + uint8_t newHash[HASH_SIZE]; + // create SHA-384 hash of JSON and xor with previous part (can be any hash - just looking for a unique key) + mbedtls_sha512_ret((uint8_t *)buffer,length, newHash,1); + for (int i=0; i<48; i++) + tHash[i] = tHash[i] ^ newHash[i]; +} + +const uint8_t* CalcHashCallContext::getHashCode() +{ + flush(); + return tHash; +} \ No newline at end of file diff --git a/src/SendEncryptedContext.h b/src/CallContext.h similarity index 56% rename from src/SendEncryptedContext.h rename to src/CallContext.h index 082c314..c657ff0 100644 --- a/src/SendEncryptedContext.h +++ b/src/CallContext.h @@ -30,27 +30,57 @@ struct HAPClient; +///////////////////////////////////////////////////////////////////////////////// +// CallContext class +// Store strings off a call and call handlePage after the page limit was reached -///////////////////////////////////////////////// -// SendEncryptedContext class -// Write encrypted data as response to a web call - -class SendEncryptedContext +class CallContext { - const int FRAME_SIZE=1024; // number of bytes to use in each ChaCha20-Poly1305 encrypted frame when sending encrypted JSON content to Client - +private: TempBuffer stringBuffer; int usedStringLength = 0; - int sentLength = 0; - HAPClient& hapClient; - TempBuffer sendBuffer; public: - SendEncryptedContext(HAPClient& hapClient); - ~SendEncryptedContext(); - + CallContext(); void printf(const char* format, ...); void print(const char* text); char* reserveStringBuffer(int stringLength); + void flush(); +protected: + virtual void handlePage(const char* buffer, int length) = 0; +}; + +///////////////////////////////////////////////////////////////////////////////// +// SendEncryptedCallContext class +// Sends the pages encrypted to the network + +class SendEncryptedCallContext : public CallContext +{ + static const int FRAME_SIZE=1024; // number of bytes to use in each ChaCha20-Poly1305 encrypted frame when sending encrypted JSON content to Client + + HAPClient& hapClient; + TempBuffer sendBuffer; +public: + SendEncryptedCallContext(HAPClient& hapClient); + ~SendEncryptedCallContext(); + + private: + virtual void handlePage(const char* buffer, int length) override; +}; + +///////////////////////////////////////////////////////////////////////////////// +// CalcHashCallContext class +// Calc an hash code out of the provided strings + +class CalcHashCallContext : public CallContext +{ +public: + static const int HASH_SIZE=48; + private: - void sendEncrypted(const char* buffer, int length); + uint8_t tHash[CalcHashCallContext::HASH_SIZE]; +public: + CalcHashCallContext(); + const uint8_t* getHashCode(); +protected: + void handlePage(const char* buffer, int length) override; }; \ No newline at end of file diff --git a/src/HAP.cpp b/src/HAP.cpp index bf2a963..9cffa37 100644 --- a/src/HAP.cpp +++ b/src/HAP.cpp @@ -876,9 +876,9 @@ int HAPClient::getAccessoriesURL(){ // free(body); - SendEncryptedContext context(*this); - context.printf("HTTP/1.1 200 OK\r\nContent-Type: application/hap+json\r\nContent-Length: %d\r\n\r\n",nBytes); - homeSpan.sprintfAttributes(NULL, GET_VALUE|GET_META|GET_PERMS|GET_TYPE|GET_DESC, &context); + SendEncryptedCallContext callContext(*this); + callContext.printf("HTTP/1.1 200 OK\r\nContent-Type: application/hap+json\r\nContent-Length: %d\r\n\r\n",nBytes); + homeSpan.sprintfAttributes(NULL, GET_VALUE|GET_META|GET_PERMS|GET_TYPE|GET_DESC, &callContext); return(1); } // getAccessories diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 2c03347..6ca6f26 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -39,7 +39,7 @@ #include "HomeSpan.h" #include "HAP.h" -#include "SendEncryptedContext.h" +#include "CallContext.h" const __attribute__((section(".rodata_custom_desc"))) SpanPartition spanPartition = {HOMESPAN_MAGIC_COOKIE,0}; @@ -1228,33 +1228,33 @@ Span& Span::setWifiCredentials(const char *ssid, const char *pwd){ /////////////////////////////// -int Span::sprintfAttributes(char *cBuf, int flags, SendEncryptedContext* sendEncryptedContext){ +int Span::sprintfAttributes(char *cBuf, int flags, CallContext* callContext){ int nBytes=0; nBytes+=snprintf(cBuf,cBuf?64:0,"{\"accessories\":["); - if (sendEncryptedContext != NULL) - sendEncryptedContext->print("{\"accessories\":["); + if (callContext != NULL) + callContext->print("{\"accessories\":["); for(int i=0;isprintfAttributes(cBuf?(cBuf+nBytes):NULL,flags); nBytes+= accessoryBytes; - if (sendEncryptedContext != NULL) + if (callContext != NULL) { - char* buffer = sendEncryptedContext->reserveStringBuffer(accessoryBytes); + char* buffer = callContext->reserveStringBuffer(accessoryBytes); accessory->sprintfAttributes(buffer, flags); } if(i+1print(","); + if (callContext != NULL) + callContext->print(","); } } nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,"]}"); - if (sendEncryptedContext != NULL) - sendEncryptedContext->print("]}"); + if (callContext != NULL) + callContext->print("]}"); return(nBytes); } @@ -1606,15 +1606,20 @@ int Span::sprintfAttributes(char **ids, int numIDs, int flags, char *cBuf){ boolean Span::updateDatabase(boolean updateMDNS){ - uint8_t tHash[48]; - TempBuffer tBuf(sprintfAttributes(NULL,GET_META|GET_PERMS|GET_TYPE|GET_DESC)+1, "Span::updateDatabase"); - sprintfAttributes(tBuf.get(),GET_META|GET_PERMS|GET_TYPE|GET_DESC); - mbedtls_sha512_ret((uint8_t *)tBuf.get(),tBuf.len(),tHash,1); // create SHA-384 hash of JSON (can be any hash - just looking for a unique key) + // uint8_t tHash[48]; + // TempBuffer tBuf(sprintfAttributes(NULL,GET_META|GET_PERMS|GET_TYPE|GET_DESC)+1, "Span::updateDatabase"); + // sprintfAttributes(tBuf.get(),GET_META|GET_PERMS|GET_TYPE|GET_DESC); + // mbedtls_sha512_ret((uint8_t *)tBuf.get(),tBuf.len(),tHash,1); // create SHA-384 hash of JSON (can be any hash - just looking for a unique key) + + + CalcHashCallContext callContext = CalcHashCallContext(); + sprintfAttributes(NULL ,GET_META|GET_PERMS|GET_TYPE|GET_DESC, &callContext); + const uint8_t* hash = callContext.getHashCode(); boolean changed=false; - if(memcmp(tHash,hapConfig.hashCode,48)){ // if hash code of current HAP database does not match stored hash code - memcpy(hapConfig.hashCode,tHash,48); // update stored hash code + if(memcmp(hash,hapConfig.hashCode,CalcHashCallContext::HASH_SIZE)){ // if hash code of current HAP database does not match stored hash code + memcpy(hapConfig.hashCode,hash,CalcHashCallContext::HASH_SIZE); // update stored hash code hapConfig.configNumber++; // increment configuration number if(hapConfig.configNumber==65536) // reached max value hapConfig.configNumber=1; // reset to 1 diff --git a/src/HomeSpan.h b/src/HomeSpan.h index f92d841..7be0be2 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -48,7 +48,7 @@ #include "extras/Pixel.h" #include "Settings.h" #include "Utils.h" -#include "SendEncryptedContext.h" +#include "CallContext.h" #include "Network.h" #include "HAPConstants.h" #include "HapQR.h" @@ -269,7 +269,7 @@ class Span{ void resetStatus(); // resets statusLED and calls statusCallback based on current HomeSpan status void reboot(); // reboots device - int sprintfAttributes(char *cBuf, int flags=GET_VALUE|GET_META|GET_PERMS|GET_TYPE|GET_DESC, SendEncryptedContext* sendEncryptedContext = nullptr); // prints Attributes JSON database into buf, unless buf=NULL; return number of characters printed, excluding null terminator + int sprintfAttributes(char *cBuf, int flags=GET_VALUE|GET_META|GET_PERMS|GET_TYPE|GET_DESC, CallContext* callContext = nullptr); // prints Attributes JSON database into buf, unless buf=NULL; return number of characters printed, excluding null terminator void prettyPrint(char *buf, int nsp=2, int minLogLevel=0); // print arbitrary JSON from buf to serial monitor, formatted with indentions of 'nsp' spaces, subject to specified minimum log level SpanCharacteristic *find(uint32_t aid, int iid); // return Characteristic with matching aid and iid (else NULL if not found)