Skip to content

Commit

Permalink
Added filesystem error handling
Browse files Browse the repository at this point in the history
Signed-off-by: AssemblyJohn <[email protected]>
  • Loading branch information
AssemblyJohn committed May 6, 2024
1 parent b56760f commit 72e0b45
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 40 deletions.
2 changes: 2 additions & 0 deletions include/evse_security/utils/evse_filesystem.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ bool is_subdirectory(const fs::path& base, const fs::path& subdir);

/// @brief Should be used to ensure file exists, not for directories
bool create_file_if_nonexistent(const fs::path& file_path);
/// @brief Ensure a file exists (if there's an extension), or a directory if no extension is found
bool create_file_or_dir_if_nonexistent(const fs::path& file_path);
bool delete_file(const fs::path& file_path);

bool read_from_file(const fs::path& file_path, std::string& out_data);
Expand Down
15 changes: 2 additions & 13 deletions lib/evse_security/certificate/x509_bundle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,8 @@ X509CertificateBundle::X509CertificateBundle(const fs::path& path, const Encodin
hierarchy_invalidated(true) {
this->path = path;

// In case the path is missing, create it
if (fs::exists(path) == false) {
if (path.has_extension()) {
if (path.extension() == PEM_EXTENSION) {
// Create file if we have an PEM extension
std::ofstream new_file(path.c_str());
new_file.close();
}
} else {
// Else create a directory
fs::create_directories(path);
}
}
// Attempt creation
filesystem_utils::create_file_or_dir_if_nonexistent(path);

if (fs::is_directory(path)) {
source = X509CertificateSource::DIRECTORY;
Expand Down
43 changes: 28 additions & 15 deletions lib/evse_security/evse_security.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,14 @@ static fs::path get_private_key_path_of_certificate(const X509Wrapper& certifica

if (fs::exists(potential_keyfile)) {
try {
fsstd::ifstream file(potential_keyfile, std::ios::binary);
std::string private_key((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
std::string private_key;

if (KeyValidationResult::Valid ==
CryptoSupplier::x509_check_private_key(certificate.get(), private_key, password)) {
EVLOG_debug << "Key found for certificate at path: " << potential_keyfile;
return potential_keyfile;
if (filesystem_utils::read_from_file(potential_keyfile, private_key)) {
if (KeyValidationResult::Valid ==
CryptoSupplier::x509_check_private_key(certificate.get(), private_key, password)) {
EVLOG_debug << "Key found for certificate at path: " << potential_keyfile;
return potential_keyfile;
}
}
} catch (const std::exception& e) {
EVLOG_debug << "Could not load or verify private key at: " << potential_keyfile << ": " << e.what();
Expand All @@ -123,13 +124,14 @@ static fs::path get_private_key_path_of_certificate(const X509Wrapper& certifica
auto key_file_path = entry.path();
if (is_keyfile(key_file_path)) {
try {
fsstd::ifstream file(key_file_path, std::ios::binary);
std::string private_key((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
std::string private_key;

if (KeyValidationResult::Valid ==
CryptoSupplier::x509_check_private_key(certificate.get(), private_key, password)) {
EVLOG_debug << "Key found for certificate at path: " << key_file_path;
return key_file_path;
if (filesystem_utils::read_from_file(key_file_path, private_key)) {
if (KeyValidationResult::Valid ==
CryptoSupplier::x509_check_private_key(certificate.get(), private_key, password)) {
EVLOG_debug << "Key found for certificate at path: " << key_file_path;
return key_file_path;
}
}
} catch (const std::exception& e) {
EVLOG_debug << "Could not load or verify private key at: " << key_file_path << ": " << e.what();
Expand All @@ -151,8 +153,11 @@ static fs::path get_private_key_path_of_certificate(const X509Wrapper& certifica
/// present in a bundle too
static std::set<fs::path> get_certificate_path_of_key(const fs::path& key, const fs::path& certificate_path_directory,
const std::optional<std::string> password) {
fsstd::ifstream file(key, std::ios::binary);
std::string private_key((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
std::string private_key;

if (false == filesystem_utils::read_from_file(key, private_key)) {
throw NoPrivateKeyException("Could not read private key from path: " + private_key);
}

// Before iterating all bundles, check by certificates from key filename
fs::path cert_filename = key;
Expand Down Expand Up @@ -819,7 +824,7 @@ void EvseSecurity::update_ocsp_cache(const CertificateHashData& certificate_hash
const auto ocsp_path = cert.get_file().value().parent_path() / "ocsp";

if (false == fs::exists(ocsp_path)) {
fs::create_directories(ocsp_path);
filesystem_utils::create_file_or_dir_if_nonexistent(ocsp_path);
} else {
// Iterate existing hashes
for (const auto& hash_entry : fs::directory_iterator(ocsp_path)) {
Expand Down Expand Up @@ -1756,14 +1761,22 @@ void EvseSecurity::garbage_collect() {
}

if (is_keyfile(key_file_path)) {
bool error = false;

try {
// Check if we have found any matching certificate
get_certificate_path_of_key(key_file_path, keys_dir, this->private_key_password);
} catch (const NoCertificateValidException& e) {
// If we did not found, add to the potential delete list
EVLOG_debug << "Could not find matching certificate for key: " << key_file_path
<< " adding to potential deletes";
error = true;
} catch (const NoPrivateKeyException& e) {
EVLOG_debug << "Could not load private key: " << key_file_path << " adding to potential deletes";
error = true;
}

if (error) {
// Give a chance to be fulfilled by the CSMS
if (managed_csr.find(key_file_path) == managed_csr.end()) {
managed_csr.emplace(key_file_path, std::chrono::steady_clock::now());
Expand Down
68 changes: 56 additions & 12 deletions lib/evse_security/utils/evse_filesystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,39 +18,83 @@ bool is_subdirectory(const fs::path& base, const fs::path& subdir) {
}

bool delete_file(const fs::path& file_path) {
if (fs::is_regular_file(file_path))
return fs::remove(file_path);
try {
if (fs::is_regular_file(file_path)) {
return fs::remove(file_path);
}
} catch (const std::exception& e) {
EVLOG_error << "Filesystem error: " << e.what();
}

EVLOG_error << "Error deleting file: " << file_path;
return false;
}

bool read_from_file(const fs::path& file_path, std::string& out_data) {
if (fs::is_regular_file(file_path)) {
fsstd::ifstream file(file_path, std::ios::binary);
try {
if (fs::is_regular_file(file_path)) {
fsstd::ifstream file(file_path, std::ios::binary);

if (file.is_open()) {
out_data = std::string((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
return true;
if (file.is_open()) {
out_data = std::string((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
return true;
}
}
} catch (const std::exception& e) {
EVLOG_error << "Error while reading from file: " << e.what();
}

EVLOG_error << "Error reading file: " << file_path;
return false;
}

bool create_file_if_nonexistent(const fs::path& file_path) {
if (!fs::exists(file_path)) {
std::ofstream file(file_path);
return true;
} else if (fs::is_directory(file_path)) {
EVLOG_error << "Attempting to create file over existing directory: " << file_path;
if (file_path.empty()) {
EVLOG_warning << "Provided empty path!";
return false;
}

try {
if (!fs::exists(file_path)) {
std::ofstream file(file_path);
return true;
} else if (fs::is_directory(file_path)) {
EVLOG_error << "Attempting to create file over existing directory: " << file_path;
return false;
}
} catch (const std::exception& e) {
EVLOG_error << "Error while creating file: " << e.what();
}

return true;
}

bool create_file_or_dir_if_nonexistent(const fs::path& path) {
if (path.empty()) {
EVLOG_warning << "Provided empty path!";
return false;
}

try {
// In case the path is missing, create it
if (fs::exists(path) == false) {
if (path.has_extension()) {
std::ofstream new_file(path.c_str());
new_file.close();
return true;
} else {
// Else create a directory
fs::create_directories(path);
return true;
}
}
} catch (const std::exception& e) {
EVLOG_error << "Error while creating dir/file: " << e.what();
}

return false;
}

bool write_to_file(const fs::path& file_path, const std::string& data, std::ios::openmode mode) {
try {
fsstd::ofstream fs(file_path, mode | std::ios::binary);
Expand Down

0 comments on commit 72e0b45

Please sign in to comment.