Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mg c07 authorize contract certs #527

Closed
wants to merge 12 commits into from
11 changes: 9 additions & 2 deletions include/ocpp/common/evse_security.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ class EvseSecurity {
/// \param certificate_chain PEM formatted certificate or certificate chain
/// \param certificate_type type of the leaf certificate
/// \return result of the operation
virtual InstallCertificateResult verify_certificate(const std::string& certificate_chain,
const CertificateSigningUseEnum& certificate_type) = 0;
virtual CertificateValidationResult verify_certificate(const std::string& certificate_chain,
const CaCertificateType& certificate_type) = 0;

/// \brief Retrieves all certificates installed on the filesystem applying the \p certificate_types filter. This
/// function respects the requirements of OCPP specified for the CSMS initiated message
Expand All @@ -62,6 +62,13 @@ class EvseSecurity {
/// \return contains OCSP request data
virtual std::vector<OCSPRequestData> get_ocsp_request_data() = 0;

/// \brief Retrieves the OCSP request data of a certificate chain.
/// \param certificate_chain PEM formatted certificate or certificate chain
/// \param certificate_type type of the leaf certificate
/// \return contains OCSP request data
virtual std::vector<OCSPRequestData> get_ocsp_request_data(const std::string& certificate_chain,
const CaCertificateType& certificate_type) = 0;

/// \brief Updates the OCSP cache for the given \p certificate_hash_data with the given \p ocsp_response
/// \param certificate_hash_data identifies the certificate for which the \p ocsp_response is specified
/// \param ocsp_response the actual OCSP data
Expand Down
7 changes: 5 additions & 2 deletions include/ocpp/common/evse_security_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,13 @@ class EvseSecurityImpl : public EvseSecurity {
DeleteCertificateResult delete_certificate(const CertificateHashDataType& certificate_hash_data) override;
InstallCertificateResult update_leaf_certificate(const std::string& certificate_chain,
const CertificateSigningUseEnum& certificate_type) override;
InstallCertificateResult verify_certificate(const std::string& certificate_chain,
const CertificateSigningUseEnum& certificate_type) override;
CertificateValidationResult verify_certificate(const std::string& certificate_chain,
const CaCertificateType& certificate_type) override;
std::vector<CertificateHashDataChain>
get_installed_certificates(const std::vector<CertificateType>& certificate_types) override;
std::vector<OCSPRequestData> get_ocsp_request_data() override;
std::vector<OCSPRequestData> get_ocsp_request_data(const std::string& certificate_chain,
const CaCertificateType& certificate_type) override;
void update_ocsp_cache(const CertificateHashDataType& certificate_hash_data,
const std::string& ocsp_response) override;
bool is_ca_certificate_installed(const CaCertificateType& certificate_type) override;
Expand All @@ -62,6 +64,7 @@ CaCertificateType to_ocpp(evse_security::CaCertificateType other);
CertificateSigningUseEnum to_ocpp(evse_security::LeafCertificateType other);
CertificateType to_ocpp(evse_security::CertificateType other);
HashAlgorithmEnumType to_ocpp(evse_security::HashAlgorithm other);
CertificateValidationResult to_ocpp(evse_security::CertificateValidationError other);
InstallCertificateResult to_ocpp(evse_security::InstallCertificateResult other);
DeleteCertificateResult to_ocpp(evse_security::DeleteCertificateResult other);

Expand Down
25 changes: 25 additions & 0 deletions include/ocpp/common/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,31 @@ CaCertificateType string_to_ca_certificate_type(const std::string& s);
/// \returns an output stream with the CaCertificateType written to
std::ostream& operator<<(std::ostream& os, const CaCertificateType& ca_certificate_type);

enum class CertificateValidationResult {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see this done before so maybe not the right time, but I think we should prevent making a copy of an enum definition at all cost. This is going to be really error prone.

If we want it in scope I would suggest using some kind of using statement here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess how I did it is similar to how it is typically done in libocpp. @Pietfried any suggestions?

Accepted,
Expired,
InvalidSignature,
IssuerNotFound,
InvalidLeafSignature,
InvalidChain,
Unknown,
};

namespace conversions {
/// \brief Converts the given InstallCertificateResult \p e to human readable string
/// \returns a string representation of the InstallCertificateResult
std::string certificate_validation_result_to_string(CertificateValidationResult e);

/// \brief Converts the given std::string \p s to InstallCertificateResult
/// \returns a InstallCertificateResult from a string representation
CertificateValidationResult string_to_certificate_validation_result(const std::string& s);
} // namespace conversions

/// \brief Writes the string representation of the given InstallCertificateResult \p
/// install_certificate_result to the given output stream \p os \returns an output stream with the
/// InstallCertificateResult written to
std::ostream& operator<<(std::ostream& os, const CertificateValidationResult& certificate_validation_result);

enum class InstallCertificateResult {
InvalidSignature,
InvalidCertificateChain,
Expand Down
5 changes: 5 additions & 0 deletions include/ocpp/v201/charge_point.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,11 @@ class ChargePoint : ocpp::ChargingStationBase {
/// \return True on success. False if evse id does not exist.
bool on_charging_state_changed(const uint32_t evse_id, ChargingStateEnum charging_state);

/// \brief Generates OCSP request data from a (contract) certificate chain
/// \param certificate
/// \return vector with OCSP request data
std::vector<OCSPRequestData> generate_ocsp_data(const CiString<5500>& certificate);

/// \brief Validates provided \p id_token \p certificate and \p ocsp_request_data using CSMS, AuthCache or AuthList
/// \param id_token
/// \param certificate
Expand Down
40 changes: 38 additions & 2 deletions lib/ocpp/common/evse_security_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ InstallCertificateResult EvseSecurityImpl::update_leaf_certificate(const std::st
this->evse_security->update_leaf_certificate(certificate_chain, conversions::from_ocpp(certificate_type)));
}

InstallCertificateResult EvseSecurityImpl::verify_certificate(const std::string& certificate_chain,
const CertificateSigningUseEnum& certificate_type) {
CertificateValidationResult EvseSecurityImpl::verify_certificate(const std::string& certificate_chain,
const CaCertificateType& certificate_type) {
return conversions::to_ocpp(
this->evse_security->verify_certificate(certificate_chain, conversions::from_ocpp(certificate_type)));
}
Expand Down Expand Up @@ -74,6 +74,20 @@ std::vector<OCSPRequestData> EvseSecurityImpl::get_ocsp_request_data() {

return result;
}

std::vector<OCSPRequestData> EvseSecurityImpl::get_ocsp_request_data(const std::string& certificate_chain,
const CaCertificateType& certificate_type) {
std::vector<OCSPRequestData> result;

const auto ocsp_request_data =
this->evse_security->get_ocsp_request_data(certificate_chain, conversions::from_ocpp(certificate_type));
for (const auto& ocsp_request_entry : ocsp_request_data.ocsp_request_data_list) {
result.push_back(conversions::to_ocpp(ocsp_request_entry));
}

return result;
}

void EvseSecurityImpl::update_ocsp_cache(const CertificateHashDataType& certificate_hash_data,
const std::string& ocsp_response) {
this->evse_security->update_ocsp_cache(conversions::from_ocpp(certificate_hash_data), ocsp_response);
Expand Down Expand Up @@ -174,6 +188,28 @@ HashAlgorithmEnumType to_ocpp(evse_security::HashAlgorithm other) {
}
}

CertificateValidationResult to_ocpp(evse_security::CertificateValidationError other) {
switch (other) {
case evse_security::CertificateValidationError::NoError:
return CertificateValidationResult::Accepted;
case evse_security::CertificateValidationError::Expired:
return CertificateValidationResult::Expired;
case evse_security::CertificateValidationError::InvalidSignature:
return CertificateValidationResult::InvalidSignature;
case evse_security::CertificateValidationError::IssuerNotFound:
return CertificateValidationResult::IssuerNotFound;
case evse_security::CertificateValidationError::InvalidLeafSignature:
return CertificateValidationResult::InvalidLeafSignature;
case evse_security::CertificateValidationError::InvalidChain:
return CertificateValidationResult::InvalidChain;
case evse_security::CertificateValidationError::Unknown:
return CertificateValidationResult::Unknown;
default:
throw std::runtime_error(
"Could not convert evse_security::CertificateValidationError to CertificateValidationResult");
}
}

InstallCertificateResult to_ocpp(evse_security::InstallCertificateResult other) {
switch (other) {
case evse_security::InstallCertificateResult::InvalidSignature:
Expand Down
55 changes: 55 additions & 0 deletions lib/ocpp/common/types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,61 @@ std::ostream& operator<<(std::ostream& os, const CaCertificateType& ca_certifica
os << conversions::ca_certificate_type_to_string(ca_certificate_type);
return os;
}

namespace conversions {
std::string certificate_validation_result_to_string(CertificateValidationResult e) {
switch (e) {
case CertificateValidationResult::Accepted:
return "Accepted";
case CertificateValidationResult::Expired:
return "Expired";
case CertificateValidationResult::InvalidSignature:
return "InvalidSignature";
case CertificateValidationResult::IssuerNotFound:
return "IssuerNotFound";
case CertificateValidationResult::InvalidLeafSignature:
return "InvalidLeafSignature";
case CertificateValidationResult::InvalidChain:
return "InvalidChain";
case CertificateValidationResult::Unknown:
return "Unknown";
}

throw std::out_of_range("No known string conversion for provided enum of type CertificateValidationResult");
}

CertificateValidationResult string_to_certificate_validation_result(const std::string& s) {
if (s == "Accepted") {
return CertificateValidationResult::Accepted;
}
if (s == "Expired") {
return CertificateValidationResult::Expired;
}
if (s == "InvalidSignature") {
return CertificateValidationResult::InvalidSignature;
}
if (s == "IssuerNotFound") {
return CertificateValidationResult::IssuerNotFound;
}
if (s == "InvalidLeafSignature") {
return CertificateValidationResult::InvalidLeafSignature;
}
if (s == "InvalidChain") {
return CertificateValidationResult::InvalidChain;
}
if (s == "Unknown") {
return CertificateValidationResult::Unknown;
}
throw std::out_of_range("Provided string " + s +
" could not be converted to enum of type CertificateValidationResult");
}
} // namespace conversions

std::ostream& operator<<(std::ostream& os, const CertificateValidationResult& certificate_validation_result) {
os << conversions::certificate_validation_result_to_string(certificate_validation_result);
return os;
}

namespace conversions {
std::string install_certificate_result_to_string(InstallCertificateResult e) {
switch (e) {
Expand Down
4 changes: 2 additions & 2 deletions lib/ocpp/v16/charge_point_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2378,8 +2378,8 @@ void ChargePointImpl::handleSignedUpdateFirmware(ocpp::Call<SignedUpdateFirmware
SignedUpdateFirmwareResponse response;

if (this->evse_security->verify_certificate(call.msg.firmware.signingCertificate.get(),
ocpp::CertificateSigningUseEnum::ManufacturerCertificate) !=
ocpp::InstallCertificateResult::Accepted) {
ocpp::CaCertificateType::MF) !=
ocpp::CertificateValidationResult::Accepted) {
response.status = UpdateFirmwareStatusEnumType::InvalidCertificate;
ocpp::CallResult<SignedUpdateFirmwareResponse> call_result(response, call.uniqueId);
this->send<SignedUpdateFirmwareResponse>(call_result);
Expand Down
Loading