Skip to content

Commit

Permalink
Add clang-format linter workflow (#4)
Browse files Browse the repository at this point in the history
* Add clang-format linter workflow
* clang-format

---------

Signed-off-by: Kai-Uwe Hermann <[email protected]>
  • Loading branch information
hikinggrass authored Sep 29, 2023
1 parent 089843f commit a91d2d1
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 82 deletions.
21 changes: 21 additions & 0 deletions .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Lint
on: [workflow_dispatch, pull_request]

jobs:
lint:
name: Lint
strategy:
matrix:
os: [ubuntu-22.04]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout libocpp
uses: actions/checkout@v3
with:
path: source
- name: Run clang-format
uses: everest/everest-ci/github-actions/[email protected]
with:
source-dir: source
extensions: hpp,cpp
exclude: cache
8 changes: 4 additions & 4 deletions include/evse_security.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class EvseSecurity {

/// @brief Retrieves all certificates installed on the filesystem applying the \p certificate_types filter.
/// @param certificate_types
/// @return contains the certificate hash data chains of the requested \p certificate_types
/// @return contains the certificate hash data chains of the requested \p certificate_types
GetInstalledCertificatesResult get_installed_certificates(const std::vector<CertificateType>& certificate_types);

/// @brief Retrieves the OCSP request data of the V2G certificates
Expand Down Expand Up @@ -114,12 +114,12 @@ class EvseSecurity {

/// @brief Retrieves the PEM formatted CA bundle file for the given \p certificate_type
/// @param certificate_type
/// @return CA certificate file
/// @return CA certificate file
std::string get_verify_file(CaCertificateType certificate_type);

/// @brief Gets the expiry day count for the leaf certificate of the given \p certificate_type
/// @param certificate_type
/// @return day count until the leaf certificate expires
/// @return day count until the leaf certificate expires
int get_leaf_expiry_days_count(LeafCertificateType certificate_type);

private:
Expand Down
15 changes: 7 additions & 8 deletions include/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,22 +87,21 @@ struct CertificateHashData {
std::string serial_number; ///< The string representation of the hexadecimal value of the serial number without the
///< prefix "0x" and without leading zeroes.

bool operator==(const CertificateHashData &Other) {
return hash_algorithm == Other.hash_algorithm
&& issuer_name_hash == Other.issuer_name_hash
&& issuer_key_hash == Other.issuer_key_hash
&& serial_number == Other.serial_number;
bool operator==(const CertificateHashData& Other) {
return hash_algorithm == Other.hash_algorithm && issuer_name_hash == Other.issuer_name_hash &&
issuer_key_hash == Other.issuer_key_hash && serial_number == Other.serial_number;
}
};
struct CertificateHashDataChain {
CertificateType certificate_type; ///< Indicates the type of the certificate for which the hash data is provided
CertificateHashData certificate_hash_data; ///< Contains the hash data of the certificate
std::vector<CertificateHashData> child_certificate_hash_data; ///< Contains the hash data of the child's certificates
CertificateHashData certificate_hash_data; ///< Contains the hash data of the certificate
std::vector<CertificateHashData>
child_certificate_hash_data; ///< Contains the hash data of the child's certificates
};
struct GetInstalledCertificatesResult {
GetInstalledCertificatesStatus status; ///< Indicates the status of the request
std::vector<CertificateHashDataChain>
certificate_hash_data_chain; ///< the hashed certificate data for each requested certificates
certificate_hash_data_chain; ///< the hashed certificate data for each requested certificates
};
struct OCSPRequestData {
std::optional<CertificateHashData> certificate_hash_data; ///< Contains the hash data of the certificate
Expand Down
10 changes: 5 additions & 5 deletions include/x509_wrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ class CertificateLoadException : public std::runtime_error {

/// @brief Convenience wrapper around openssl X509 certificate. Can contain multiple certificates
class X509Wrapper {
using X509_ptr = std::unique_ptr<X509, decltype(&::X509_free)>;
using X509_ptr = std::unique_ptr<X509, decltype(&::X509_free)>;

public:
// Constructors
X509Wrapper(const std::string& certificate, const EncodingFormat encoding);
Expand All @@ -35,7 +36,7 @@ class X509Wrapper {

X509Wrapper(const X509Wrapper& other);
X509Wrapper(X509Wrapper&& other) = default;

~X509Wrapper();

/// @brief Gets raw X509 pointer
Expand Down Expand Up @@ -96,8 +97,7 @@ class X509Wrapper {

/// @brief Gets if this certificate file is containing multiple certificates
/// @return
bool is_bundle()
{
bool is_bundle() {
return x509.size() > 1;
}

Expand All @@ -109,7 +109,7 @@ class X509Wrapper {
std::vector<X509_ptr> x509;
int valid_in; // seconds; if > 0 cert is not yet valid
int valid_to; // seconds; if < 0 cert has expired
std::optional<std::filesystem::path> path;
std::optional<std::filesystem::path> path;
};

} // namespace evse_security
Expand Down
65 changes: 33 additions & 32 deletions lib/evse_security.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,14 +182,13 @@ static CertificateType get_certificate_type(const CaCertificateType ca_certifica
static std::string get_random_file_name(const std::string& extension) {
char path[] = "XXXXXX";
mktemp(path);

return std::string(path) + extension;
}


std::vector<X509Wrapper> get_leaf_certificates(const std::filesystem::path &cert_dir) {
std::vector<X509Wrapper> get_leaf_certificates(const std::filesystem::path& cert_dir) {
std::vector<X509Wrapper> certificates;

for (const auto& entry : std::filesystem::recursive_directory_iterator(cert_dir)) {
if (std::filesystem::is_regular_file(entry)) {
const auto cert_path = entry.path();
Expand All @@ -212,10 +211,10 @@ std::vector<X509Wrapper> get_leaf_certificates(const std::filesystem::path &cert
std::vector<X509Wrapper> get_leaf_certificates(std::vector<std::filesystem::path> paths) {
std::vector<X509Wrapper> certificates;

for(const auto &path : paths) {
for (const auto& path : paths) {
auto certifs = get_leaf_certificates(path);

if(certifs.size() > 0) {
if (certifs.size() > 0) {
certificates.reserve(certificates.size() + certifs.size());
std::move(std::begin(certifs), std::end(certifs), std::back_inserter(certificates));
}
Expand All @@ -224,17 +223,19 @@ std::vector<X509Wrapper> get_leaf_certificates(std::vector<std::filesystem::path
return certificates;
}

std::vector<X509Wrapper> get_ca_certificates(const std::map<CaCertificateType, std::filesystem::path> &ca_bundle_path_map) {
std::vector<X509Wrapper>
get_ca_certificates(const std::map<CaCertificateType, std::filesystem::path>& ca_bundle_path_map) {
// x509 wrapper specific
std::vector<X509Wrapper> ca_certificates;
for (auto const& [certificate_type, ca_bundle_path] : ca_bundle_path_map) {
try {
X509Wrapper ca_bundle(ca_bundle_path, EncodingFormat::PEM);
const auto certificates_of_bundle = ca_bundle.split();

if(certificates_of_bundle.size() > 0) {
if (certificates_of_bundle.size() > 0) {
ca_certificates.reserve(ca_certificates.size() + certificates_of_bundle.size());
std::move(std::begin(certificates_of_bundle), std::end(certificates_of_bundle), std::back_inserter(ca_certificates));
std::move(std::begin(certificates_of_bundle), std::end(certificates_of_bundle),
std::back_inserter(ca_certificates));
}
} catch (const CertificateLoadException& e) {
EVLOG_info << "Could not load ca bundle from file: " << ca_bundle_path;
Expand All @@ -245,17 +246,18 @@ std::vector<X509Wrapper> get_ca_certificates(const std::map<CaCertificateType, s

EvseSecurity::EvseSecurity(const FilePaths& file_paths, const std::optional<std::string>& private_key_password) :
private_key_password(private_key_password) {

std::vector<std::filesystem::path> dirs = { file_paths.directories.csms_leaf_cert_directory,
file_paths.directories.csms_leaf_key_directory,
file_paths.directories.secc_leaf_cert_directory,
file_paths.directories.secc_leaf_key_directory, };

for(const auto &path : dirs) {
std::vector<std::filesystem::path> dirs = {
file_paths.directories.csms_leaf_cert_directory,
file_paths.directories.csms_leaf_key_directory,
file_paths.directories.secc_leaf_cert_directory,
file_paths.directories.secc_leaf_key_directory,
};

for (const auto& path : dirs) {
if (!std::filesystem::exists(path)) {
throw std::runtime_error("Could not find configured leaf directory at: " + path.string());
}
else if(!std::filesystem::is_directory(path)) {
} else if (!std::filesystem::is_directory(path)) {
throw std::runtime_error(path.string() + " is not a directory.");
}
}
Expand All @@ -265,16 +267,15 @@ EvseSecurity::EvseSecurity(const FilePaths& file_paths, const std::optional<std:
this->ca_bundle_path_map[CaCertificateType::MO] = file_paths.mo_ca_bundle;
this->ca_bundle_path_map[CaCertificateType::V2G] = file_paths.v2g_ca_bundle;

for(const auto& pair : this->ca_bundle_path_map) {
if(!std::filesystem::exists(pair.second)) {
throw std::runtime_error("Could not find configured " + std::to_string((int)pair.first) + " bundle file at: " +
file_paths.csms_ca_bundle.string());
}
else if(std::filesystem::is_directory(pair.second)) {
throw std::runtime_error("Provided bundle " + std::to_string((int)pair.first) + " is directory: " +
file_paths.csms_ca_bundle.string());
for (const auto& pair : this->ca_bundle_path_map) {
if (!std::filesystem::exists(pair.second)) {
throw std::runtime_error("Could not find configured " + std::to_string((int)pair.first) +
" bundle file at: " + file_paths.csms_ca_bundle.string());
} else if (std::filesystem::is_directory(pair.second)) {
throw std::runtime_error("Provided bundle " + std::to_string((int)pair.first) +
" is directory: " + file_paths.csms_ca_bundle.string());
}
}
}

this->directories = file_paths.directories;
}
Expand Down Expand Up @@ -321,7 +322,8 @@ DeleteCertificateResult EvseSecurity::delete_certificate(const CertificateHashDa
}
}

const auto leaf_certificates = get_leaf_certificates({directories.secc_leaf_cert_directory, directories.csms_leaf_cert_directory});
const auto leaf_certificates =
get_leaf_certificates({directories.secc_leaf_cert_directory, directories.csms_leaf_cert_directory});
for (const auto& leaf_certificate : leaf_certificates) {
if (leaf_certificate.get_issuer_name_hash() == certificate_hash_data.issuer_name_hash and
leaf_certificate.get_issuer_key_hash() == certificate_hash_data.issuer_key_hash and
Expand Down Expand Up @@ -372,7 +374,7 @@ InstallCertificateResult EvseSecurity::update_leaf_certificate(const std::string
return result;
}

const auto &leaf_certificate = _certificate_chain[0];
const auto& leaf_certificate = _certificate_chain[0];

// check if a private key belongs to the provided certificate
try {
Expand Down Expand Up @@ -401,8 +403,7 @@ InstallCertificateResult EvseSecurity::update_leaf_certificate(const std::string
return InstallCertificateResult::Accepted;
}

GetInstalledCertificatesResult
EvseSecurity::get_installed_certificate(CertificateType certificate_type) {
GetInstalledCertificatesResult EvseSecurity::get_installed_certificate(CertificateType certificate_type) {
return get_installed_certificates({certificate_type});
}

Expand Down Expand Up @@ -667,8 +668,8 @@ int EvseSecurity::get_leaf_expiry_days_count(LeafCertificateType certificate_typ
}

InstallCertificateResult EvseSecurity::verify_certificate(const std::string& certificate_chain,
LeafCertificateType certificate_type) {
try {
LeafCertificateType certificate_type) {
try {
X509Wrapper certificate(certificate_chain, EncodingFormat::PEM);
std::vector<X509Wrapper> _certificate_chain = certificate.split();
if (_certificate_chain.empty()) {
Expand Down
36 changes: 17 additions & 19 deletions lib/x509_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@
#include <everest/logging.hpp>

#include <openssl/err.h>
#include <x509_wrapper.hpp>
#include <openssl/x509v3.h>
#include <x509_wrapper.hpp>

namespace evse_security {

using BIO_ptr = std::unique_ptr<BIO, decltype(&::BIO_free)>;

std::string x509_to_string(X509 *x509) {
std::string x509_to_string(X509* x509) {
if (x509) {
BIO_ptr bio_write(BIO_new(BIO_s_mem()), ::BIO_free);
BIO_ptr bio_write(BIO_new(BIO_s_mem()), ::BIO_free);

int rc = PEM_write_bio_X509(bio_write.get(), x509);

Expand All @@ -32,16 +32,15 @@ std::string x509_to_string(X509 *x509) {
return {};
}

void X509Wrapper::update_validity()
{
void X509Wrapper::update_validity() {
// For valid_in and valid_to
ASN1_TIME* notBefore = X509_get_notBefore(x509[0].get());
ASN1_TIME* notAfter = X509_get_notAfter(x509[0].get());
int day, sec;
ASN1_TIME_diff(&day, &sec, notBefore, nullptr);
this->valid_in = day * 86400 + sec; // Convert days to seconds
ASN1_TIME_diff(&day, &sec, nullptr, notAfter);
this->valid_to = day * 86400 + sec; // Convert days to seconds
this->valid_to = day * 86400 + sec; // Convert days to seconds
}

// Load a certificate from a string using the specified encoding.
Expand All @@ -60,26 +59,26 @@ void X509Wrapper::load_certificate(const std::string& data, const EncodingFormat
X509_INFO* xi = sk_X509_INFO_value(allcerts, i);

if (xi && xi->x509) {
// Transfer owneship
// Transfer owneship
x509.emplace_back(xi->x509, ::X509_free);
xi->x509 = nullptr;
}
}

sk_X509_INFO_pop_free(allcerts, X509_INFO_free);
sk_X509_INFO_pop_free(allcerts, X509_INFO_free);
} else {
throw CertificateLoadException("Unsupported encoding format");
}
} else if (encoding == EncodingFormat::DER) {
x509.emplace_back(d2i_X509_bio(bio.get(), nullptr), ::X509_free);
} else {
} else {
throw CertificateLoadException("Unsupported encoding format");
}

if (!x509.size()) {
throw CertificateLoadException("Failed to read X509 from BIO");
}

update_validity();
}

Expand All @@ -89,8 +88,8 @@ X509Wrapper::X509Wrapper(const std::string& certificate, const EncodingFormat en

X509Wrapper::X509Wrapper(const std::filesystem::path& path, const EncodingFormat encoding) {
// TODO: Directory support
if(std::filesystem::is_directory(path)) {
if (std::filesystem::is_directory(path)) {

} else {
std::ifstream file(path, std::ios::binary);
std::string certificate((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
Expand All @@ -105,22 +104,21 @@ X509Wrapper::X509Wrapper(X509* x509) {
update_validity();
}

X509Wrapper::X509Wrapper(const X509Wrapper& other) {
for(const auto &cert : other.x509) {
X509 *dup_cert = X509_dup(cert.get());
X509Wrapper::X509Wrapper(const X509Wrapper& other) {
for (const auto& cert : other.x509) {
X509* dup_cert = X509_dup(cert.get());
x509.emplace_back(dup_cert, ::X509_free);
}

if (other.path) {
path = other.path.value();
}

valid_in = other.valid_in;
valid_to = other.valid_to;
}

X509Wrapper::~X509Wrapper() {

}

X509* X509Wrapper::get() const {
Expand All @@ -134,9 +132,9 @@ void X509Wrapper::reset(X509* _x509) {
std::vector<X509Wrapper> X509Wrapper::split() {
std::vector<X509Wrapper> certificates;

for(const auto &cert : x509) {
for (const auto& cert : x509) {
// Duplicates since a X509Wrapper requires exclusive ownership
X509 *dup_cert = X509_dup(cert.get());
X509* dup_cert = X509_dup(cert.get());
certificates.emplace_back(dup_cert);

if (this->path.has_value()) {
Expand Down
Loading

0 comments on commit a91d2d1

Please sign in to comment.