Load sensitive data from the SPIFFS
Sensitive data are WiFi Logins and authentication data. This is done in preparation for the OTA update, where the firmware image will be transferred unencrypted and therefore passwords could be extracted from a dumped image.
This commit is contained in:
parent
8a1a17bb07
commit
24ba2242a4
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -4,5 +4,5 @@
|
||||||
.vscode/launch.json
|
.vscode/launch.json
|
||||||
.vscode/ipch
|
.vscode/ipch
|
||||||
|
|
||||||
include/WLAN_Logins.h
|
data/etc/*
|
||||||
include/Crypto_Config.h
|
!data/etc/.*
|
||||||
|
|
15
README.md
15
README.md
|
@ -2,7 +2,16 @@
|
||||||
|
|
||||||
## Setup notes
|
## 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`
|
### `data/etc/wlan`
|
||||||
- `include/Crypto_Config.h.example`
|
|
||||||
|
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.
|
||||||
|
|
0
data/etc/.keep
Normal file
0
data/etc/.keep
Normal file
36
include/Config.h
Normal file
36
include/Config.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class Config
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct WLAN
|
||||||
|
{
|
||||||
|
std::string ssid;
|
||||||
|
std::string password;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<WLAN> 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;
|
||||||
|
};
|
|
@ -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";
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
struct NetInfo {
|
|
||||||
const char *ssid;
|
|
||||||
const char *password;
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::array<NetInfo, 2> NETWORKS {
|
|
||||||
NetInfo{"SomeNetwork", "ThePassword"},
|
|
||||||
NetInfo{"SomeOtherNetwork", "TheOtherPassword"}
|
|
||||||
};
|
|
|
@ -9,11 +9,12 @@ import re
|
||||||
IP = sys.argv[1]
|
IP = sys.argv[1]
|
||||||
|
|
||||||
# read the salt from the header file
|
# read the salt from the header file
|
||||||
with open("../include/Crypto_Config.h", "r") as header:
|
with open("../data/etc/auth", "r") as authFile:
|
||||||
for line in header:
|
lineno = 0
|
||||||
if "SALT" in line:
|
for line in authFile:
|
||||||
mo = re.search(r'"(.*)"', line)
|
if lineno == 1:
|
||||||
SALT = mo.groups()[0]
|
SALT = line.strip()
|
||||||
|
lineno += 1
|
||||||
|
|
||||||
print(f'SALT = "{SALT}"')
|
print(f'SALT = "{SALT}"')
|
||||||
|
|
||||||
|
@ -35,4 +36,4 @@ m.update(responsestr.encode('utf-8'))
|
||||||
response = m.hexdigest()
|
response = m.hexdigest()
|
||||||
|
|
||||||
result = requests.get(f"http://{IP}/authtest", {"response": response})
|
result = requests.get(f"http://{IP}/authtest", {"response": response})
|
||||||
print(result.text)
|
print(result.text)
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
#include "ChallengeResponse.h"
|
#include "ChallengeResponse.h"
|
||||||
|
|
||||||
#include "Crypto_Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
ChallengeResponse::ChallengeResponse(const std::string &pw)
|
ChallengeResponse::ChallengeResponse(const std::string &pw)
|
||||||
: m_passwd(pw), m_expireTime(0)
|
: m_passwd(pw), m_expireTime(0)
|
||||||
|
@ -21,7 +21,7 @@ bool ChallengeResponse::verify(const std::string &hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostringstream refResponse;
|
std::ostringstream refResponse;
|
||||||
refResponse << m_passwd << ":" << m_currentNonce << ":" << crypto::SALT;
|
refResponse << m_passwd << ":" << m_currentNonce << ":" << Config::instance().getCRSalt();
|
||||||
|
|
||||||
// calculate hash of reference response
|
// calculate hash of reference response
|
||||||
uint8_t sha256sum[32];
|
uint8_t sha256sum[32];
|
||||||
|
|
44
src/Config.cpp
Normal file
44
src/Config.cpp
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#include <SPIFFS.h>
|
||||||
|
|
||||||
|
#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();
|
||||||
|
}
|
|
@ -5,12 +5,12 @@
|
||||||
|
|
||||||
#include "WebServer.h"
|
#include "WebServer.h"
|
||||||
|
|
||||||
#include "Crypto_Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
#include "Fader.h"
|
#include "Fader.h"
|
||||||
|
|
||||||
WebServer::WebServer(void)
|
WebServer::WebServer(void)
|
||||||
: m_cr(crypto::HTTP_PASSWORD), m_fader(NULL)
|
: m_cr(Config::instance().getCRPassword()), m_fader(NULL)
|
||||||
{
|
{
|
||||||
m_server = new httpsserver::HTTPServer();
|
m_server = new httpsserver::HTTPServer();
|
||||||
}
|
}
|
||||||
|
|
11
src/main.cpp
11
src/main.cpp
|
@ -5,10 +5,10 @@
|
||||||
#include <WiFiMulti.h>
|
#include <WiFiMulti.h>
|
||||||
#include <SPIFFS.h>
|
#include <SPIFFS.h>
|
||||||
|
|
||||||
#include "WLAN_Logins.h"
|
|
||||||
#include "WebServer.h"
|
#include "WebServer.h"
|
||||||
#include "Fader.h"
|
#include "Fader.h"
|
||||||
#include "UDPProto.h"
|
#include "UDPProto.h"
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
#include <esp32_digital_led_lib.h>
|
#include <esp32_digital_led_lib.h>
|
||||||
#include <esp32_digital_led_funcs.h>
|
#include <esp32_digital_led_funcs.h>
|
||||||
|
@ -193,6 +193,9 @@ void setup()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// load configuration (especially crypto data)
|
||||||
|
Config::instance().load();
|
||||||
|
|
||||||
digitalWrite(2, HIGH);
|
digitalWrite(2, HIGH);
|
||||||
|
|
||||||
Serial.println();
|
Serial.println();
|
||||||
|
@ -210,11 +213,11 @@ void setup()
|
||||||
NULL); /* Task handle to keep track of created task */
|
NULL); /* Task handle to keep track of created task */
|
||||||
|
|
||||||
// Connect the WiFi network (or start an AP if that doesn't work)
|
// 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.print("Adding network ");
|
||||||
Serial.println(net.ssid);
|
Serial.println(net.ssid.c_str());
|
||||||
wiFiMulti.addAP(net.ssid, net.password);
|
wiFiMulti.addAP(net.ssid.c_str(), net.password.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
wifi_setup();
|
wifi_setup();
|
||||||
|
|
Loading…
Reference in a new issue