diff --git a/.gitignore b/.gitignore index 4c60841..567c20a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,5 @@ .vscode/launch.json .vscode/ipch -include/WLAN_Logins.h -include/Crypto_Config.h +data/etc/* +!data/etc/.* diff --git a/README.md b/README.md index 1ac9059..58eccf3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,16 @@ ## Setup notes -On the files below, remove the `.example` part of the name and adjust to your needs: +Authentication data for WiFi connections and OTA firmware updates is stored in the SPIFFS. You must create the following files: -- `include/WLAN_Logins.h.example` -- `include/Crypto_Config.h.example` +### `data/etc/wlan` + +This file contains WiFi logins. Each entry consists of two lines: The first line contains the SSID to connect to, the second the password. + +### `data/etc/auth` + +This file configures the authentication at the device. For now, this is used for OTA updates. + +The file contains two lines: First the password, second the salt. + +The salt must be known to any client performing OTA updates and can be stored in a local configuration file. The password should never be stored in any config file. diff --git a/data/etc/.keep b/data/etc/.keep new file mode 100644 index 0000000..e69de29 diff --git a/include/Config.h b/include/Config.h new file mode 100644 index 0000000..78f5f09 --- /dev/null +++ b/include/Config.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include + +class Config +{ + public: + struct WLAN + { + std::string ssid; + std::string password; + }; + + typedef std::vector WLANList; + + static Config &instance() + { + static Config theConfig; + return theConfig; + } + + void load(void); + + const WLANList& getWLANList(void) { return m_wlans; } + + const std::string& getCRPassword(void) { return m_crPassword; } + const std::string& getCRSalt(void) { return m_crSalt; } + + private: + Config(); + + WLANList m_wlans; + std::string m_crPassword; + std::string m_crSalt; +}; \ No newline at end of file diff --git a/include/Crypto_Config.h.example b/include/Crypto_Config.h.example deleted file mode 100644 index 031e505..0000000 --- a/include/Crypto_Config.h.example +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -namespace crypto -{ - // replace these with your own values! - static const char * const HTTP_PASSWORD = "secure!1"; - static const char * const SALT = "1234567890abcdefghijklmnopqrstuv"; -} \ No newline at end of file diff --git a/include/WLAN_Logins.h.example b/include/WLAN_Logins.h.example deleted file mode 100644 index c48d3b4..0000000 --- a/include/WLAN_Logins.h.example +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -struct NetInfo { - const char *ssid; - const char *password; -}; - -const std::array NETWORKS { - NetInfo{"SomeNetwork", "ThePassword"}, - NetInfo{"SomeOtherNetwork", "TheOtherPassword"} -}; diff --git a/scripts/authtest.py b/scripts/authtest.py index 3f9918e..b7dc333 100755 --- a/scripts/authtest.py +++ b/scripts/authtest.py @@ -9,11 +9,12 @@ import re IP = sys.argv[1] # read the salt from the header file -with open("../include/Crypto_Config.h", "r") as header: - for line in header: - if "SALT" in line: - mo = re.search(r'"(.*)"', line) - SALT = mo.groups()[0] +with open("../data/etc/auth", "r") as authFile: + lineno = 0 + for line in authFile: + if lineno == 1: + SALT = line.strip() + lineno += 1 print(f'SALT = "{SALT}"') @@ -35,4 +36,4 @@ m.update(responsestr.encode('utf-8')) response = m.hexdigest() result = requests.get(f"http://{IP}/authtest", {"response": response}) -print(result.text) \ No newline at end of file +print(result.text) diff --git a/src/ChallengeResponse.cpp b/src/ChallengeResponse.cpp index 3ca8ee8..47775ff 100644 --- a/src/ChallengeResponse.cpp +++ b/src/ChallengeResponse.cpp @@ -6,7 +6,7 @@ #include "ChallengeResponse.h" -#include "Crypto_Config.h" +#include "Config.h" ChallengeResponse::ChallengeResponse(const std::string &pw) : m_passwd(pw), m_expireTime(0) @@ -21,7 +21,7 @@ bool ChallengeResponse::verify(const std::string &hash) } std::ostringstream refResponse; - refResponse << m_passwd << ":" << m_currentNonce << ":" << crypto::SALT; + refResponse << m_passwd << ":" << m_currentNonce << ":" << Config::instance().getCRSalt(); // calculate hash of reference response uint8_t sha256sum[32]; diff --git a/src/Config.cpp b/src/Config.cpp new file mode 100644 index 0000000..88bf4e9 --- /dev/null +++ b/src/Config.cpp @@ -0,0 +1,44 @@ +#include + +#include "Config.h" + +Config::Config() +{} + +void Config::load(void) +{ + // load WLANs + File wlanFile = SPIFFS.open("/etc/wlan", "r"); + + while(wlanFile.available()) { + String ssid = wlanFile.readStringUntil('\n'); + + if(!wlanFile.available()) { + Serial.println("/etc/wlan terminated early. Last entry ignored."); + break; + } + + String passwd = wlanFile.readStringUntil('\n'); + + m_wlans.emplace_back(WLAN{ssid.c_str(), passwd.c_str()}); + } + + wlanFile.close(); + + // load Challenge-Response data + File authFile = SPIFFS.open("/etc/auth", "r"); + + if(authFile.available()) { + String passwd = authFile.readStringUntil('\n'); + m_crPassword = passwd.c_str(); + + if(!authFile.available()) { + m_crSalt = ""; + } else { + String salt = authFile.readStringUntil('\n'); + m_crSalt = salt.c_str(); + } + } + + authFile.close(); +} \ No newline at end of file diff --git a/src/WebServer.cpp b/src/WebServer.cpp index b040a5d..27596c7 100644 --- a/src/WebServer.cpp +++ b/src/WebServer.cpp @@ -5,12 +5,12 @@ #include "WebServer.h" -#include "Crypto_Config.h" +#include "Config.h" #include "Fader.h" WebServer::WebServer(void) - : m_cr(crypto::HTTP_PASSWORD), m_fader(NULL) + : m_cr(Config::instance().getCRPassword()), m_fader(NULL) { m_server = new httpsserver::HTTPServer(); } diff --git a/src/main.cpp b/src/main.cpp index 96ae08a..1bad3c0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,10 +5,10 @@ #include #include -#include "WLAN_Logins.h" #include "WebServer.h" #include "Fader.h" #include "UDPProto.h" +#include "Config.h" #include #include @@ -193,6 +193,9 @@ void setup() } } + // load configuration (especially crypto data) + Config::instance().load(); + digitalWrite(2, HIGH); Serial.println(); @@ -210,11 +213,11 @@ void setup() NULL); /* Task handle to keep track of created task */ // Connect the WiFi network (or start an AP if that doesn't work) - for (auto &net : NETWORKS) + for (auto &net : Config::instance().getWLANList()) { Serial.print("Adding network "); - Serial.println(net.ssid); - wiFiMulti.addAP(net.ssid, net.password); + Serial.println(net.ssid.c_str()); + wiFiMulti.addAP(net.ssid.c_str(), net.password.c_str()); } wifi_setup();