diff --git a/include/controller.h b/include/controller.h index 946aff8..ecef935 100644 --- a/include/controller.h +++ b/include/controller.h @@ -4,12 +4,13 @@ #include "servo.h" #include "message.h" #include "storage.h" +#include "fresh.h" #include class SesameController: public ServerConnectionCallbacks { public: - SesameController(ServerConnection* server, ServoController* servo, AsyncWebServer* local, uint8_t remoteDeviceCount); + SesameController(ServerConnection* server, ServoController* servo, AsyncWebServer* local, TimeCheck* timeCheck, uint8_t remoteDeviceCount); void configure(); @@ -18,6 +19,7 @@ private: ServerConnection* server; ServoController* servo; AsyncWebServer* local; + TimeCheck* timeCheck; Storage storage; // The buffer to hold a received message while it is read diff --git a/include/fresh.h b/include/fresh.h index 6eaa9da..6c2c367 100644 --- a/include/fresh.h +++ b/include/fresh.h @@ -3,50 +3,81 @@ #include #include "config.h" -/** - * @brief Configure an NTP server to get the current time - * - * @param offsetToGMT The timezone offset in seconds - * @param offsetDaylightSavings The daylight savings offset in seconds - * @param serverUrl The url of the NTP server - */ -void configureNTP(int32_t offsetToGMT, int32_t offsetDaylightSavings, const char* serverUrl); +class TimeCheck { -/** - * @brief Print the current time to the serial output - * - * The time must be initialized by calling `configureNTP()` before use. - */ -void printLocalTime(); +public: -/** - * Gets the current epoch time - */ -uint32_t getEpochTime(); + /** + * @brief Create a time checker instance + * + * Specify the allowed discrepancy between the time of a received message + * and the device time (in seconds). + * + * A stricter (lower) value better prevents against replay attacks, + * but may lead to issues when dealing with slow networks and other + * routing delays. + * + * @param offset The allowed time discrepancy in both directions (seconds) + */ + TimeCheck(uint32_t allowedTimeOffset = 60); -/** - * @brief The allowed time discrepancy (in seconds) - * - * Specifies the allowed discrepancy between the time of a received message - * and the device time (in seconds). - * - * A stricter (lower) value better prevents against replay attacks, - * but may lead to issues when dealing with slow networks and other - * routing delays. - * - * @param offset The offset in both directions (seconds) - */ -void setMessageTimeAllowedOffset(uint32_t offset); + /** + * @brief Configure an NTP server to get the current time + * + * @param offsetToGMT The timezone offset in seconds + * @param offsetDaylightSavings The daylight savings offset in seconds + * @param serverUrl The url of the NTP server + */ + void configureNTP(int32_t offsetToGMT, int32_t offsetDaylightSavings, const char* serverUrl); -/** - * @brief Check wether the time of a message is within the allowed bounds regarding freshness. - * - * The timestamp is used to ensure 'freshness' of the messages, - * i.e. that they are not unreasonably delayed or captured and - * later replayed by an attacker. - * - * @param messageTime The timestamp of the message (seconds since epoch) - * @return true The time is within the acceptable offset of the local time - * @return false The message time is invalid - */ -bool isMessageTimeAcceptable(uint32_t messageTime); \ No newline at end of file + /** + * @brief Print the current time to the serial output + * + * The time must be initialized by calling `configureNTP()` before use. + */ + void printLocalTime(); + + /** + * Gets the current epoch time + */ + uint32_t getEpochTime(); + + /** + * @brief The allowed time discrepancy (in seconds) + * + * Specifies the allowed discrepancy between the time of a received message + * and the device time (in seconds). + * + * A stricter (lower) value better prevents against replay attacks, + * but may lead to issues when dealing with slow networks and other + * routing delays. + * + * @param offset The offset in both directions (seconds) + */ + void setMessageTimeAllowedOffset(uint32_t offset); + + /** + * @brief Check wether the time of a message is within the allowed bounds regarding freshness. + * + * The timestamp is used to ensure 'freshness' of the messages, + * i.e. that they are not unreasonably delayed or captured and + * later replayed by an attacker. + * + * @param messageTime The timestamp of the message (seconds since epoch) + * @return true The time is within the acceptable offset of the local time + * @return false The message time is invalid + */ + bool isMessageTimeAcceptable(uint32_t messageTime); + +private: + + /** + * @brief The allowed discrepancy between the time of a received message + * and the device time (in seconds) + * + * A stricter (lower) value better prevents against replay attacks, + * but may lead to issues when dealing with slow networks and other + * routing delays. + */ + uint32_t allowedOffset; +}; \ No newline at end of file diff --git a/src/controller.cpp b/src/controller.cpp index 9697a0f..98657d9 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -3,8 +3,8 @@ #include "fresh.h" #include "crypto.h" -SesameController::SesameController(ServerConnection* server, ServoController* servo, AsyncWebServer* local, uint8_t remoteDeviceCount) : - server(server), servo(servo), local(local), storage(remoteDeviceCount) { +SesameController::SesameController(ServerConnection* server, ServoController* servo, AsyncWebServer* local, TimeCheck* timeCheck, uint8_t remoteDeviceCount) : + server(server), servo(servo), local(local), timeCheck(timeCheck), storage(remoteDeviceCount) { // Set up response buffer responseStatus = (SesameEvent*) responseBuffer; @@ -99,7 +99,7 @@ SesameEvent SesameController::verifyAndProcessReceivedMessage(AuthenticatedMessa if (!storage.isMessageCounterValid(message->message.id, message->message.device)) { return SesameEvent::MessageCounterInvalid; } - if (!isMessageTimeAcceptable(message->message.time)) { + if (!timeCheck->isMessageTimeAcceptable(message->message.time)) { return SesameEvent::MessageTimeMismatch; } @@ -127,7 +127,7 @@ uint16_t SesameController::prepareResponseBuffer(SesameEvent event, uint8_t devi if (!allowMessageResponse(event)) { return 1; } - responseMessage->message.time = getEpochTime(); + responseMessage->message.time = timeCheck->getEpochTime(); responseMessage->message.id = storage.getNextMessageCounter(deviceId); responseMessage->message.device = deviceId; if (!authenticateMessage(responseMessage, localKey, keySize)) { diff --git a/src/fresh.cpp b/src/fresh.cpp index 8b770f2..bf69599 100644 --- a/src/fresh.cpp +++ b/src/fresh.cpp @@ -1,27 +1,17 @@ #include "fresh.h" -#include +#include // configTime() #include -/** - * @brief The allowed discrepancy between the time of a received message - * and the device time (in seconds) - * - * A stricter (lower) value better prevents against replay attacks, - * but may lead to issues when dealing with slow networks and other - * routing delays. - */ -uint32_t allowedOffset = 60; - -void setMessageTimeAllowedOffset(uint32_t offset) { - allowedOffset = offset; +TimeCheck::TimeCheck(uint32_t allowedTimeOffset) { + allowedOffset = allowedTimeOffset; } -void configureNTP(int32_t offsetToGMT, int32_t offsetDaylightSavings, const char* serverUrl) { +void TimeCheck::configureNTP(int32_t offsetToGMT, int32_t offsetDaylightSavings, const char* serverUrl) { configTime(offsetToGMT, offsetDaylightSavings, serverUrl); } -void printLocalTime() { +void TimeCheck::printLocalTime() { struct tm timeinfo; if (getLocalTime(&timeinfo)) { Serial.println(&timeinfo, "[INFO] Time is %A, %d. %B %Y %H:%M:%S"); @@ -30,7 +20,7 @@ void printLocalTime() { } } -uint32_t getEpochTime() { +uint32_t TimeCheck::getEpochTime() { time_t now; struct tm timeinfo; if (!getLocalTime(&timeinfo)) { @@ -41,7 +31,7 @@ uint32_t getEpochTime() { return now; } -bool isMessageTimeAcceptable(uint32_t t) { +bool TimeCheck::isMessageTimeAcceptable(uint32_t t) { uint32_t localTime = getEpochTime(); if (localTime == 0) { Serial.println("No epoch time available"); diff --git a/src/main.cpp b/src/main.cpp index fc2ba50..29bd9b5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,13 +19,15 @@ /* Global variables */ +TimeCheck timeCheck{}; + ServerConnection server(serverUrl, serverPort, serverPath); ServoController servo(pwmTimer, servoFrequency, servoPin); AsyncWebServer local(localPort); -SesameController controller(&server, &servo, &local, remoteDeviceCount); +SesameController controller(&server, &servo, &local, &timeCheck, remoteDeviceCount); // Forward declare monitoring functions void ensureWiFiConnection(uint32_t time); @@ -75,8 +77,8 @@ void ensureWebSocketConnection(uint32_t time) { Serial.println(WiFi.localIP()); Serial.println("[INFO] WiFi connected, opening socket"); server.connect(serverAccessKey); - configureNTP(timeOffsetToGMT, timeOffsetDaylightSavings, ntpServerUrl); - printLocalTime(); + timeCheck.configureNTP(timeOffsetToGMT, timeOffsetDaylightSavings, ntpServerUrl); + timeCheck.printLocalTime(); local.begin(); } } \ No newline at end of file