mirror of
https://github.com/wled/WLED.git
synced 2025-07-08 03:16:32 +00:00
HMAC fixes
This commit is contained in:
parent
f3429a6c93
commit
fd624aa94b
@ -438,6 +438,11 @@
|
|||||||
#define ERR_OVERTEMP 30 // An attached temperature sensor has measured above threshold temperature (not implemented)
|
#define ERR_OVERTEMP 30 // An attached temperature sensor has measured above threshold temperature (not implemented)
|
||||||
#define ERR_OVERCURRENT 31 // An attached current sensor has measured a current above the threshold (not implemented)
|
#define ERR_OVERCURRENT 31 // An attached current sensor has measured a current above the threshold (not implemented)
|
||||||
#define ERR_UNDERVOLT 32 // An attached voltmeter has measured a voltage below the threshold (not implemented)
|
#define ERR_UNDERVOLT 32 // An attached voltmeter has measured a voltage below the threshold (not implemented)
|
||||||
|
#define ERR_NONCE 40 // Invalid nonce
|
||||||
|
#define ERR_REPLAY 41 // Replay attack detected
|
||||||
|
#define ERR_HMAC 42 // HMAC verification failed
|
||||||
|
#define ERR_HMAC_MISS 43 // HMAC missing
|
||||||
|
#define ERR_HMAC_GEN 44 // HMAC handling error
|
||||||
|
|
||||||
// Timer mode types
|
// Timer mode types
|
||||||
#define NL_MODE_SET 0 //After nightlight time elapsed, set to target brightness
|
#define NL_MODE_SET 0 //After nightlight time elapsed, set to target brightness
|
||||||
|
@ -3,6 +3,74 @@
|
|||||||
|
|
||||||
#define HMAC_KEY_SIZE 32
|
#define HMAC_KEY_SIZE 32
|
||||||
|
|
||||||
|
#define SESSION_ID_SIZE 16
|
||||||
|
#define MAX_SESSION_IDS 8
|
||||||
|
|
||||||
|
void getNonce(byte* nonce) {
|
||||||
|
RNG::fill(nonce, SESSION_ID_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Nonce {
|
||||||
|
byte sessionId[SESSION_ID_SIZE];
|
||||||
|
uint32_t counter;
|
||||||
|
};
|
||||||
|
|
||||||
|
Nonce knownSessions[MAX_SESSION_IDS] = {};
|
||||||
|
|
||||||
|
void moveToFirst(uint32_t i) {
|
||||||
|
if (i >= MAX_SESSION_IDS) return;
|
||||||
|
|
||||||
|
Nonce tmp = knownSessions[i];
|
||||||
|
for (int j = i; j > 0; j--) {
|
||||||
|
knownSessions[j] = knownSessions[j - 1];
|
||||||
|
}
|
||||||
|
knownSessions[0] = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool verifyNonce(const byte* sid, uint32_t counter) {
|
||||||
|
for (int i = 0; i < MAX_SESSION_IDS; i++) {
|
||||||
|
if (memcmp(knownSessions[i].sessionId, sid, SESSION_ID_SIZE) == 0) {
|
||||||
|
if (counter <= knownSessions[i].counter) {
|
||||||
|
Serial.println(F("Retransmission detected!"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
knownSessions[i].counter = counter;
|
||||||
|
// nonce good, move this entry to the first position of knownSessions
|
||||||
|
moveToFirst(i);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Serial.println(F("Unknown session ID!"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addSession(const char* sid) {
|
||||||
|
byte sid_new[SESSION_ID_SIZE];
|
||||||
|
RNG::fill(sid_new, SESSION_ID_SIZE);
|
||||||
|
|
||||||
|
// first, try to find a completely unused slot
|
||||||
|
for (int i = 0; i < MAX_SESSION_IDS; i++) {
|
||||||
|
// this is not perfect, but it is extremely unlikely that the first 32 bit of a random session ID are all zeroes
|
||||||
|
if ((uint32_t)(knownSessions[i].sessionId) == 0 && knownSessions[i].counter == 0) {
|
||||||
|
memcpy(knownSessions[i].sessionId, sid, SESSION_ID_SIZE);
|
||||||
|
moveToFirst(i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// next, find oldest slot that has counter 0 (not used before)
|
||||||
|
// but leave the two most recent slots alone
|
||||||
|
for (int i = MAX_SESSION_IDS - 1; i > 1; i--) {
|
||||||
|
if (knownSessions[i].counter == 0) {
|
||||||
|
memcpy(knownSessions[i].sessionId, sid, SESSION_ID_SIZE);
|
||||||
|
moveToFirst(i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if all else fails, overwrite the oldest slot
|
||||||
|
memcpy(knownSessions[MAX_SESSION_IDS - 1].sessionId, sid, SESSION_ID_SIZE);
|
||||||
|
moveToFirst(MAX_SESSION_IDS - 1);
|
||||||
|
}
|
||||||
|
|
||||||
void printByteArray(const byte* arr, size_t len) {
|
void printByteArray(const byte* arr, size_t len) {
|
||||||
for (size_t i = 0; i < len; i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
Serial.print(arr[i], HEX);
|
Serial.print(arr[i], HEX);
|
||||||
@ -34,8 +102,8 @@ void hmacSign(const byte* message, size_t msgLen, const char* pskHex, byte* sign
|
|||||||
bool hmacVerify(const byte* message, size_t msgLen, const char* pskHex, const byte* signature) {
|
bool hmacVerify(const byte* message, size_t msgLen, const char* pskHex, const byte* signature) {
|
||||||
byte sigCalculated[SHA256HMAC_SIZE];
|
byte sigCalculated[SHA256HMAC_SIZE];
|
||||||
hmacSign(message, msgLen, pskHex, sigCalculated);
|
hmacSign(message, msgLen, pskHex, sigCalculated);
|
||||||
Serial.print(F("Calculated: "));
|
//Serial.print(F("Calculated: "));
|
||||||
printByteArray(sigCalculated, SHA256HMAC_SIZE);
|
//printByteArray(sigCalculated, SHA256HMAC_SIZE);
|
||||||
if (memcmp(sigCalculated, signature, SHA256HMAC_SIZE) != 0) {
|
if (memcmp(sigCalculated, signature, SHA256HMAC_SIZE) != 0) {
|
||||||
Serial.println(F("HMAC verification failed!"));
|
Serial.println(F("HMAC verification failed!"));
|
||||||
Serial.print(F("Expected: "));
|
Serial.print(F("Expected: "));
|
||||||
@ -49,16 +117,16 @@ bool hmacVerify(const byte* message, size_t msgLen, const char* pskHex, const by
|
|||||||
#define WLED_HMAC_TEST_PW "guessihadthekeyafterall"
|
#define WLED_HMAC_TEST_PW "guessihadthekeyafterall"
|
||||||
#define WLED_HMAC_TEST_PSK "a6f8488da62c5888d7f640276676e78da8639faf0495110b43e226b35ac37a4c"
|
#define WLED_HMAC_TEST_PSK "a6f8488da62c5888d7f640276676e78da8639faf0495110b43e226b35ac37a4c"
|
||||||
|
|
||||||
bool verifyHmacFromJsonString0Term(byte* jsonStr, size_t len) {
|
uint8_t verifyHmacFromJsonString0Term(byte* jsonStr, size_t len) {
|
||||||
// Zero-terminate the JSON string (replace the last character, usually '}', with a null terminator temporarily)
|
// Zero-terminate the JSON string (replace the last character, usually '}', with a null terminator temporarily)
|
||||||
char lastChar = jsonStr[len-1];
|
byte lastChar = jsonStr[len-1];
|
||||||
jsonStr[len-1] = '\0';
|
jsonStr[len-1] = '\0';
|
||||||
bool result = verifyHmacFromJsonStr((const char*)jsonStr, len);
|
uint8_t result = verifyHmacFromJsonStr((const char*)jsonStr, len);
|
||||||
jsonStr[len-1] = lastChar;
|
jsonStr[len-1] = lastChar;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool verifyHmacFromJsonStr(const char* jsonStr, uint32_t maxLen) {
|
uint8_t verifyHmacFromJsonStr(const char* jsonStr, uint32_t maxLen) {
|
||||||
// Extract the signature from the JSON string
|
// Extract the signature from the JSON string
|
||||||
size_t jsonLen = strlen(jsonStr);
|
size_t jsonLen = strlen(jsonStr);
|
||||||
Serial.print(F("Length: "));
|
Serial.print(F("Length: "));
|
||||||
@ -67,27 +135,27 @@ bool verifyHmacFromJsonStr(const char* jsonStr, uint32_t maxLen) {
|
|||||||
Serial.print(F("JSON string too long!"));
|
Serial.print(F("JSON string too long!"));
|
||||||
Serial.print(F(", max: "));
|
Serial.print(F(", max: "));
|
||||||
Serial.println(maxLen);
|
Serial.println(maxLen);
|
||||||
return false;
|
return ERR_HMAC_GEN;
|
||||||
}
|
}
|
||||||
Serial.print(F("Received JSON: "));
|
Serial.print(F("Received JSON: "));
|
||||||
Serial.println(jsonStr);
|
Serial.println(jsonStr);
|
||||||
|
|
||||||
char* macPos = strstr(jsonStr, "\"mac\":\"");
|
const char* macPos = strstr(jsonStr, "\"mac\":\"");
|
||||||
if (macPos == nullptr) {
|
if (macPos == nullptr) {
|
||||||
Serial.println(F("No MAC found in JSON."));
|
Serial.println(F("No MAC found in JSON."));
|
||||||
return false;
|
return ERR_HMAC_MISS;
|
||||||
}
|
}
|
||||||
StaticJsonDocument<256> doc;
|
StaticJsonDocument<128> macDoc;
|
||||||
DeserializationError error = deserializeJson(doc, macPos +6);
|
DeserializationError error = deserializeJson(macDoc, macPos +6);
|
||||||
if (error) {
|
if (error) {
|
||||||
Serial.print(F("deserializeJson() failed: "));
|
Serial.print(F("deserializeJson() failed: "));
|
||||||
Serial.println(error.c_str());
|
Serial.println(error.c_str());
|
||||||
return false;
|
return ERR_HMAC_GEN;
|
||||||
}
|
}
|
||||||
const char* mac = doc.as<const char*>();
|
const char* mac = macDoc.as<const char*>();
|
||||||
if (mac == nullptr) {
|
if (mac == nullptr) {
|
||||||
Serial.println(F("Failed MAC JSON."));
|
Serial.println(F("Failed MAC JSON."));
|
||||||
return false;
|
return ERR_HMAC_GEN;
|
||||||
}
|
}
|
||||||
Serial.print(F("Received MAC: "));
|
Serial.print(F("Received MAC: "));
|
||||||
Serial.println(mac);
|
Serial.println(mac);
|
||||||
@ -97,7 +165,7 @@ bool verifyHmacFromJsonStr(const char* jsonStr, uint32_t maxLen) {
|
|||||||
char* objStart = strchr(msgPos + 6, '{');
|
char* objStart = strchr(msgPos + 6, '{');
|
||||||
if (objStart == nullptr) {
|
if (objStart == nullptr) {
|
||||||
Serial.println(F("Couldn't find msg object start."));
|
Serial.println(F("Couldn't find msg object start."));
|
||||||
return false;
|
return ERR_HMAC_GEN;
|
||||||
}
|
}
|
||||||
size_t maxObjLen = jsonLen - (objStart - jsonStr);
|
size_t maxObjLen = jsonLen - (objStart - jsonStr);
|
||||||
Serial.print(F("Max object length: ")); Serial.println(maxObjLen);
|
Serial.print(F("Max object length: ")); Serial.println(maxObjLen);
|
||||||
@ -118,20 +186,62 @@ bool verifyHmacFromJsonStr(const char* jsonStr, uint32_t maxLen) {
|
|||||||
}
|
}
|
||||||
if (objEnd == nullptr) {
|
if (objEnd == nullptr) {
|
||||||
Serial.println(F("Couldn't find msg object end."));
|
Serial.println(F("Couldn't find msg object end."));
|
||||||
return false;
|
return ERR_HMAC_GEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get nonce (note: the nonce implementation uses "nc" for the key instead of "n" to avoid conflicts with segment names)
|
||||||
|
const char* noncePos = strstr(objStart, "\"nc\":");
|
||||||
|
if (noncePos == nullptr || noncePos > objEnd) {
|
||||||
|
// note that it is critical to check that the nonce is within the "msg" object and thus authenticated
|
||||||
|
Serial.println(F("No nonce found in msg."));
|
||||||
|
return ERR_HMAC_GEN;
|
||||||
|
}
|
||||||
|
// {
|
||||||
|
// StaticJsonDocument<128> nonceDoc;
|
||||||
|
// DeserializationError error = deserializeJson(nonceDoc, noncePos +5);
|
||||||
|
// if (error) {
|
||||||
|
// Serial.print(F("deser nc failed: "));
|
||||||
|
// Serial.println(error.c_str());
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// JsonObject nonceObj = nonceDoc.as<JsonObject>();
|
||||||
|
// if (nonceObj.isNull()) {
|
||||||
|
// Serial.println(F("Failed nonce JSON."));
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// const char* sessionId = nonceObj["sid"];
|
||||||
|
// if (sessionId == nullptr) {
|
||||||
|
// Serial.println(F("No session ID found in nonce."));
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// uint32_t counter = nonceObj["c"] | 0;
|
||||||
|
// if (counter == 0) {
|
||||||
|
// Serial.println(F("No counter found in nonce."));
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// if (counter > UINT32_MAX - 100) {
|
||||||
|
// Serial.println(F("Counter too large."));
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// byte sidBytes[SESSION_ID_SIZE];
|
||||||
|
// hexStringToByteArray(sessionId, sidBytes, SESSION_ID_SIZE);
|
||||||
|
// if (!verifyNonce(sidBytes, counter)) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
// Convert the MAC from hex string to byte array
|
// Convert the MAC from hex string to byte array
|
||||||
size_t len = strlen(mac) / 2; // This will drop the last character if the string has an odd length
|
size_t len = strlen(mac) / 2; // This will drop the last character if the string has an odd length
|
||||||
if (len != SHA256HMAC_SIZE) {
|
if (len != SHA256HMAC_SIZE) {
|
||||||
Serial.println(F("Received MAC not expected size!"));
|
Serial.println(F("Received MAC not expected size!"));
|
||||||
return false;
|
return ERR_HMAC_GEN;
|
||||||
}
|
}
|
||||||
unsigned char macByteArray[len];
|
unsigned char macByteArray[len];
|
||||||
hexStringToByteArray(mac, macByteArray, len);
|
hexStringToByteArray(mac, macByteArray, len);
|
||||||
|
|
||||||
// Calculate the HMAC of the message object
|
// Calculate the HMAC of the message object
|
||||||
return hmacVerify((const byte*)objStart, objEnd - objStart + 1, WLED_HMAC_TEST_PSK, macByteArray);
|
bool hmacOk = hmacVerify((const byte*)objStart, objEnd - objStart + 1, WLED_HMAC_TEST_PSK, macByteArray);
|
||||||
|
return hmacOk ? ERR_NONE : ERR_HMAC;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hmacTest() {
|
bool hmacTest() {
|
||||||
@ -153,3 +263,32 @@ bool hmacTest() {
|
|||||||
Serial.println(F("ms to verify MAC."));
|
Serial.println(F("ms to verify MAC."));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void printDuration(unsigned long start) {
|
||||||
|
unsigned long end = millis();
|
||||||
|
Serial.print(F("Took "));
|
||||||
|
Serial.print(end - start);
|
||||||
|
Serial.println(F(" ms."));
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
#define HMAC_BENCH_ITERATIONS 100
|
||||||
|
|
||||||
|
void hmacBenchmark(const char* message) {
|
||||||
|
Serial.print(F("Starting HMAC benchmark with message length:"));
|
||||||
|
Serial.println(strlen(message));
|
||||||
|
Serial.println(F("100 iterations signing message."));
|
||||||
|
unsigned long start = millis();
|
||||||
|
byte mac[SHA256HMAC_SIZE];
|
||||||
|
for (int i = 0; i < HMAC_BENCH_ITERATIONS; i++) {
|
||||||
|
hmacSign((const byte*)message, strlen(message), WLED_HMAC_TEST_PSK, mac);
|
||||||
|
}
|
||||||
|
printDuration(start);
|
||||||
|
|
||||||
|
Serial.println(F("100 iterations verifying message."));
|
||||||
|
start = millis();
|
||||||
|
for (int i = 0; i < HMAC_BENCH_ITERATIONS; i++) {
|
||||||
|
hmacVerify((const byte*)message, strlen(message), WLED_HMAC_TEST_PSK, mac);
|
||||||
|
}
|
||||||
|
printDuration(start);
|
||||||
|
}
|
@ -327,6 +327,7 @@ function handleWindowMessageEvent(event) {
|
|||||||
sraOrigin = event.origin;
|
sraOrigin = event.origin;
|
||||||
} else if (json['wled-rc'] === 'hmac') {
|
} else if (json['wled-rc'] === 'hmac') {
|
||||||
console.log(`Received HMAC: ${json['mac']}`);
|
console.log(`Received HMAC: ${json['mac']}`);
|
||||||
|
// Pass the message containing the HMAC to the ESP
|
||||||
requestJson(json);
|
requestJson(json);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@
|
|||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||||
//console.info("Peek uses top WS");
|
//console.info("Peek uses top WS");
|
||||||
ws.send("{'lv':true}");
|
ws.send('{"lv":true}');
|
||||||
} else {
|
} else {
|
||||||
//console.info("Peek WS opening");
|
//console.info("Peek WS opening");
|
||||||
let l = window.location;
|
let l = window.location;
|
||||||
@ -80,7 +80,7 @@
|
|||||||
ws = new WebSocket(url+"/ws");
|
ws = new WebSocket(url+"/ws");
|
||||||
ws.onopen = function () {
|
ws.onopen = function () {
|
||||||
//console.info("Peek WS open");
|
//console.info("Peek WS open");
|
||||||
ws.send("{'lv':true}");
|
ws.send('{"lv":true}');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ws.binaryType = "arraybuffer";
|
ws.binaryType = "arraybuffer";
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
ws = top.window.ws;
|
ws = top.window.ws;
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||||
ws.send("{'lv':true}");
|
ws.send('{"lv":true}');
|
||||||
} else {
|
} else {
|
||||||
let l = window.location;
|
let l = window.location;
|
||||||
let pathn = l.pathname;
|
let pathn = l.pathname;
|
||||||
@ -42,7 +42,7 @@
|
|||||||
}
|
}
|
||||||
ws = new WebSocket(url+"/ws");
|
ws = new WebSocket(url+"/ws");
|
||||||
ws.onopen = ()=>{
|
ws.onopen = ()=>{
|
||||||
ws.send("{'lv':true}");
|
ws.send('{"lv":true}');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ws.binaryType = "arraybuffer";
|
ws.binaryType = "arraybuffer";
|
||||||
|
@ -98,9 +98,10 @@ void setRandomColor(byte* rgb);
|
|||||||
//crypto.cpp
|
//crypto.cpp
|
||||||
void hmacSign(const byte* message, size_t msgLen, const char* pskHex, byte* signature);
|
void hmacSign(const byte* message, size_t msgLen, const char* pskHex, byte* signature);
|
||||||
bool hmacVerify(const byte* message, size_t msgLen, const char* pskHex, const byte* signature);
|
bool hmacVerify(const byte* message, size_t msgLen, const char* pskHex, const byte* signature);
|
||||||
bool verifyHmacFromJsonStr(const char* jsonStr, uint32_t maxLen);
|
uint8_t verifyHmacFromJsonStr(const char* jsonStr, uint32_t maxLen);
|
||||||
bool verifyHmacFromJsonString0Term(byte* jsonStr, size_t len);
|
uint8_t verifyHmacFromJsonString0Term(byte* jsonStr, size_t len);
|
||||||
bool hmacTest();
|
bool hmacTest();
|
||||||
|
void hmacBenchmark(const char* message);
|
||||||
|
|
||||||
//dmx.cpp
|
//dmx.cpp
|
||||||
void initDMX();
|
void initDMX();
|
||||||
|
@ -359,6 +359,13 @@ void WLED::setup()
|
|||||||
#if !defined(WLED_DEBUG) && defined(ARDUINO_ARCH_ESP32) && !defined(WLED_DEBUG_HOST) && ARDUINO_USB_CDC_ON_BOOT
|
#if !defined(WLED_DEBUG) && defined(ARDUINO_ARCH_ESP32) && !defined(WLED_DEBUG_HOST) && ARDUINO_USB_CDC_ON_BOOT
|
||||||
Serial.setDebugOutput(false); // switch off kernel messages when using USBCDC
|
Serial.setDebugOutput(false); // switch off kernel messages when using USBCDC
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
|
//hmacTest();
|
||||||
|
//const char testMsg[] = "WLED HMAC test!!";
|
||||||
|
//hmacBenchmark(testMsg);
|
||||||
|
//const char longMsg[] = "LoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIps";
|
||||||
|
//hmacBenchmark(longMsg);
|
||||||
|
}
|
||||||
DEBUG_PRINTLN();
|
DEBUG_PRINTLN();
|
||||||
DEBUG_PRINTF_P(PSTR("---WLED %s %u INIT---\n"), versionString, VERSION);
|
DEBUG_PRINTF_P(PSTR("---WLED %s %u INIT---\n"), versionString, VERSION);
|
||||||
DEBUG_PRINTLN();
|
DEBUG_PRINTLN();
|
||||||
@ -555,8 +562,6 @@ void WLED::setup()
|
|||||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DISABLE_BROWNOUT_DET)
|
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DISABLE_BROWNOUT_DET)
|
||||||
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 1); //enable brownout detector
|
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 1); //enable brownout detector
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
hmacTest();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WLED::beginStrip()
|
void WLED::beginStrip()
|
||||||
|
@ -11,6 +11,22 @@ unsigned long wsLastLiveTime = 0;
|
|||||||
|
|
||||||
#define WS_LIVE_INTERVAL 40
|
#define WS_LIVE_INTERVAL 40
|
||||||
|
|
||||||
|
void sendWsError(AsyncWebSocketClient * client, uint8_t error)
|
||||||
|
{
|
||||||
|
if (!ws.count()) return;
|
||||||
|
|
||||||
|
char errorStr[16];
|
||||||
|
strcpy_P(errorStr, PSTR("{\"error\":"));
|
||||||
|
strcpy(errorStr + 9, itoa(error, errorStr + 9, 10));
|
||||||
|
strcat(errorStr + 10, "}");
|
||||||
|
|
||||||
|
if (client) {
|
||||||
|
client->text(errorStr); // ERR_NOBUF
|
||||||
|
} else {
|
||||||
|
ws.textAll(errorStr); // ERR_NOBUF
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len)
|
void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len)
|
||||||
{
|
{
|
||||||
if(type == WS_EVT_CONNECT){
|
if(type == WS_EVT_CONNECT){
|
||||||
@ -36,36 +52,47 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool verboseResponse = false;
|
bool verboseResponse = false;
|
||||||
if (!requestJSONBufferLock(11)) {
|
|
||||||
client->text(F("{\"error\":3}")); // ERR_NOBUF
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Serial.print(F("WS message: "));
|
Serial.print(F("WS message: "));
|
||||||
Serial.println((const char*)data);
|
Serial.write(data, len);
|
||||||
verifyHmacFromJsonString0Term(data, len);
|
Serial.println();
|
||||||
|
|
||||||
DeserializationError error = deserializeJson(*pDoc, data, len);
|
if (len < 11 && memcmp(data, "{\"v\":true}", 10) == 0) {
|
||||||
verifyHmacFromJsonString0Term(data, len);
|
|
||||||
JsonObject root = pDoc->as<JsonObject>();
|
|
||||||
if (error || root.isNull()) {
|
|
||||||
releaseJSONBufferLock();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (root["v"] && root.size() == 1) {
|
|
||||||
// if the received value is just "{"v":true}", send only to this client
|
// if the received value is just "{"v":true}", send only to this client
|
||||||
verboseResponse = true;
|
verboseResponse = true;
|
||||||
} else if (root.containsKey("lv")) {
|
Serial.println(F("Simple state query."));
|
||||||
wsLiveClientId = root["lv"] ? client->id() : 0;
|
} else if (len < 13 && memcmp(data, "{\"lv\":", 6) == 0) {
|
||||||
|
wsLiveClientId = data[6] == 't' ? client->id() : 0;
|
||||||
} else {
|
} else {
|
||||||
// if (!verifyHmacFromJsonString0Term(data, len)) {
|
// check HMAC, must do before parsing JSON as that modifies "data" to store strings
|
||||||
// releaseJSONBufferLock();
|
uint8_t hmacVerificationResult = verifyHmacFromJsonString0Term(data, len);
|
||||||
// client->text(F("{\"error\":1}")); // ERR_DENIED
|
if (hmacVerificationResult != ERR_NONE) {
|
||||||
// return;
|
sendWsError(client, hmacVerificationResult);
|
||||||
// }
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!requestJSONBufferLock(11)) {
|
||||||
|
sendWsError(client, 3); // ERR_NOBUF
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.print(F("deser input: "));
|
||||||
|
Serial.write(data, len);
|
||||||
|
Serial.println();
|
||||||
|
DeserializationError error = deserializeJson(*pDoc, data, len);
|
||||||
|
JsonObject root = pDoc->as<JsonObject>();
|
||||||
|
if (error || root.isNull()) {
|
||||||
|
Serial.print(F("deserializeJson() failed: "));
|
||||||
|
Serial.println(error.c_str());
|
||||||
|
//Serial.println(F("WS JSON parse F!"));
|
||||||
|
sendWsError(client, 9); // ERR_JSON
|
||||||
|
releaseJSONBufferLock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
verboseResponse = deserializeState(root["msg"]);
|
verboseResponse = deserializeState(root["msg"]);
|
||||||
|
|
||||||
|
releaseJSONBufferLock();
|
||||||
}
|
}
|
||||||
releaseJSONBufferLock();
|
|
||||||
|
|
||||||
if (!interfaceUpdateCallMode) { // individual client response only needed if no WS broadcast soon
|
if (!interfaceUpdateCallMode) { // individual client response only needed if no WS broadcast soon
|
||||||
if (verboseResponse) {
|
if (verboseResponse) {
|
||||||
@ -92,7 +119,7 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
|||||||
if((info->index + len) == info->len){
|
if((info->index + len) == info->len){
|
||||||
if(info->final){
|
if(info->final){
|
||||||
if(info->message_opcode == WS_TEXT) {
|
if(info->message_opcode == WS_TEXT) {
|
||||||
client->text(F("{\"error\":9}")); // ERR_JSON we do not handle split packets right now
|
sendWsError(client, 9); // ERR_JSON we do not handle split packets right now
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user