Skip to content

Commit

Permalink
Added saving and loading certificates to flash
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremypoulter committed Jul 21, 2023
1 parent 51bdd5d commit c13b707
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 11 deletions.
105 changes: 100 additions & 5 deletions src/certificates.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#endif

#include <Arduino.h>
#include <LittleFS.h>

#include "emonesp.h"
#include "certificates.h"
#include "root_ca.h"
Expand Down Expand Up @@ -79,7 +81,7 @@ bool CertificateStore::Certificate::serialize(JsonObject &doc, uint32_t flags)
doc["name"] = _name;
doc["certificate"] = _cert;
if(_type == Type::Client) {
doc["key"] = flags & Flags::REDACT_PRIVATE_KEY ? "__REDACTED__" : _key;
doc["key"] = flags & Flags::REDACT_PRIVATE_KEY ? "__REDACTED__" : _key.c_str();
}

return true;
Expand Down Expand Up @@ -109,7 +111,11 @@ CertificateStore::~CertificateStore()

bool CertificateStore::begin()
{
return true;
if(loadCertificates()) {
return true;
}

return false;
}

const char *CertificateStore::getRootCa()
Expand Down Expand Up @@ -145,14 +151,14 @@ bool CertificateStore::addCertificate(const char *name, const char *certificate,
return false;
}

bool CertificateStore::addCertificate(DynamicJsonDocument &doc, uint64_t *id)
bool CertificateStore::addCertificate(DynamicJsonDocument &doc, uint64_t *id, bool save)
{
Certificate *cert = new Certificate();
if(cert)
{
if(cert->deserialize(doc))
{
if(addCertificate(cert, id)) {
if(addCertificate(cert, id, save)) {
return true;
}
}
Expand All @@ -162,7 +168,7 @@ bool CertificateStore::addCertificate(DynamicJsonDocument &doc, uint64_t *id)
return false;
}

bool CertificateStore::addCertificate(Certificate *cert, uint64_t *id)
bool CertificateStore::addCertificate(Certificate *cert, uint64_t *id, bool save)
{
uint64_t certId = cert->getId();
if(findCertificate(certId, cert)) {
Expand All @@ -180,6 +186,10 @@ bool CertificateStore::addCertificate(Certificate *cert, uint64_t *id)
buildRootCa();
}

if(save) {
return saveCertificate(cert);
}

return true;
}

Expand All @@ -198,6 +208,7 @@ bool CertificateStore::removeCertificate(uint64_t id)
buildRootCa();
}

removeCertificate(cert);
delete cert;

return true;
Expand Down Expand Up @@ -352,3 +363,87 @@ bool CertificateStore::buildRootCa()
_root_ca = new_root_ca;
return true;
}

bool CertificateStore::loadCertificates()
{
bool loaded = true;

File certificateDir = LittleFS.open(CERTIFICATE_BASE_DIRECTORY);
if(certificateDir && certificateDir.isDirectory())
{
File file = certificateDir.openNextFile();
while(file)
{
if(!file.isDirectory())
{
String name = file.name();
DBUGVAR(name.c_str());
if(false == loadCertificate(name)) {
loaded = false;
}
}

file = certificateDir.openNextFile();
}
} else {
LittleFS.mkdir(CERTIFICATE_BASE_DIRECTORY);
}

return loaded;
}

bool CertificateStore::loadCertificate(String &name)
{
bool loaded = false;

String path = String(CERTIFICATE_BASE_DIRECTORY) + "/" + name;
DBUGF("Loading certificate %s", path.c_str());

File file = LittleFS.open(path);
if(file)
{
DynamicJsonDocument doc(CERTIFICATE_JSON_BUFFER_SIZE);
DeserializationError err = deserializeJson(doc, file);
if(DeserializationError::Code::Ok == err)
{
#ifdef ENABLE_DEBUG
DBUG("Certificate loaded: ");
serializeJson(doc, DEBUG_PORT);
DBUGLN("");
#endif
loaded = addCertificate(doc, nullptr, false);
}

file.close();
}

return loaded;
}

bool CertificateStore::saveCertificate(Certificate *cert)
{
String name = String(CERTIFICATE_BASE_DIRECTORY) + "/" + String(cert->getId(), HEX) + ".json";
File file = LittleFS.open(name, "w");
if(file)
{
DynamicJsonDocument doc(CERTIFICATE_JSON_BUFFER_SIZE);
JsonObject object = doc.to<JsonObject>();
cert->serialize(object, Certificate::Flags::SHOW_PRIVATE_KEY);
serializeJson(doc, file);
file.close();
return true;
}

return false;
}

bool CertificateStore::removeCertificate(Certificate *cert)
{
String name = String(CERTIFICATE_BASE_DIRECTORY) + "/" + String(cert->getId(), HEX) + ".json";
if(LittleFS.remove(name))
{
return true;
}

return false;
}
10 changes: 7 additions & 3 deletions src/certificates.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class CertificateStore
class Flags
{
public:
static const uint32_t SHOW_PRIVATE_KEY = 0;
static const uint32_t REDACT_PRIVATE_KEY = 1 << 0;
};

Expand Down Expand Up @@ -110,7 +111,7 @@ class CertificateStore

bool addCertificate(const char *name, const char *cert, const char *key, uint64_t *id = nullptr);
bool addCertificate(const char *name, const char *cert, uint64_t *id = nullptr);
bool addCertificate(DynamicJsonDocument &doc, uint64_t *id = nullptr);
bool addCertificate(DynamicJsonDocument &doc, uint64_t *id = nullptr, bool save = true);

bool removeCertificate(uint64_t id);

Expand All @@ -125,9 +126,12 @@ class CertificateStore

private:
bool loadCertificates();
bool saveCertificates();

bool addCertificate(Certificate *cert, uint64_t *id);
bool loadCertificate(String &name);
bool saveCertificate(Certificate *cert);
bool removeCertificate(Certificate *cert);

bool addCertificate(Certificate *cert, uint64_t *id, bool save = true);

bool findCertificate(uint64_t id, Certificate *&cert);
bool findCertificate(uint64_t id, int &index);
Expand Down
8 changes: 8 additions & 0 deletions src/emonesp.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,14 @@
#define SCHEDULE_PATH "/schedule.json"
#endif // !SCHEDULE_PATH

#ifndef CERTIFICATE_BASE_DIRECTORY
#define CERTIFICATE_BASE_DIRECTORY "/certificates"
#endif // !CERTIFICATE_BASE_DIRECTORY

#ifndef CERTIFICATE_JSON_BUFFER_SIZE
#define CERTIFICATE_JSON_BUFFER_SIZE (8 * 1024)
#endif

extern String currentfirmware;
extern String buildenv;
extern String serial;
Expand Down
5 changes: 2 additions & 3 deletions src/web_server_certificates.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ void handleCertificatesGetRootCa(MongooseHttpServerRequest *request, MongooseHtt
// -------------------------------------------------------------------
void handleCertificatesGet(MongooseHttpServerRequest *request, MongooseHttpServerResponseStream *response, uint64_t certificate)
{
const size_t capacity = 16 * 1024;
DynamicJsonDocument doc(capacity);
DynamicJsonDocument doc(4 * CERTIFICATE_JSON_BUFFER_SIZE);

bool success = (UINT64_MAX == certificate) ?
certs.serializeCertificates(doc) :
Expand All @@ -51,7 +50,7 @@ void handleCertificatesPost(MongooseHttpServerRequest *request, MongooseHttpServ

if(UINT64_MAX == certificate)
{
DynamicJsonDocument doc(8 * 1024);
DynamicJsonDocument doc(CERTIFICATE_JSON_BUFFER_SIZE);
DeserializationError jsonError = deserializeJson(doc, body);
if(DeserializationError::Ok == jsonError)
{
Expand Down

0 comments on commit c13b707

Please sign in to comment.