@@ -22,11 +22,15 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2222SOFTWARE.
2323*/
2424
25+ #include " Base64.h"
2526#include " CentralSystemDemoConfig.h"
2627#include " CentralSystemEventsHandler.h"
28+ #include " Certificate.h"
29+ #include " CertificateRequest.h"
2730#include " ChargePointDatabase.h"
2831#include " Database.h"
2932#include " ICentralSystem.h"
33+ #include " PrivateKey.h"
3034#include " TimerPool.h"
3135#include " WorkerThreadPool.h"
3236
@@ -39,9 +43,19 @@ using namespace ocpp::centralsystem;
3943using namespace ocpp ::types;
4044using namespace ocpp ::x509;
4145
46+ /* * @brief Passphrase for the certificates' private keys */
47+ static constexpr const char * PRIVATE_KEYS_PASSPHRASE =
48+ " It would have been better to have a different passphrase for each certificate...but is simplier for the example!" ;
49+
4250/* * @brief Indicate if a change of configuration has been accepted by the charge point */
4351static bool isConfigurationChangeAccepted (ConfigurationStatus status);
4452
53+ /* * @brief Create the certificates for the signed update firmware procedure */
54+ static void createSignedUpdateFirmwareCertificates (std::filesystem::path fw_update_ca,
55+ std::filesystem::path fw_update_ca_key,
56+ std::filesystem::path fw_update_cert,
57+ std::filesystem::path fw_update_cert_key);
58+
4559/* * @brief Entry point */
4660int main (int argc, char * argv[])
4761{
@@ -99,6 +113,27 @@ int main(int argc, char* argv[])
99113 std::cout << " Starting central system with :" << std::endl;
100114 std::cout << " - working_dir = " << working_dir << std::endl;
101115
116+ // Generate certificates for signed firmware update
117+ std::filesystem::path fw_update_ca (working_dir);
118+ fw_update_ca /= " fw_update_ca.pem" ;
119+ std::filesystem::path fw_update_ca_key (working_dir);
120+ fw_update_ca_key /= " fw_update_ca.key" ;
121+ std::filesystem::path fw_update_cert (working_dir);
122+ fw_update_cert /= " fw_update_cert.pem" ;
123+ std::filesystem::path fw_update_cert_key (working_dir);
124+ fw_update_cert_key /= " fw_update_cert_key.key" ;
125+ if (reset_all)
126+ {
127+ std::filesystem::remove (fw_update_ca);
128+ std::filesystem::remove (fw_update_ca_key);
129+ std::filesystem::remove (fw_update_cert);
130+ std::filesystem::remove (fw_update_cert_key);
131+ }
132+ if (!std::filesystem::exists (fw_update_ca))
133+ {
134+ createSignedUpdateFirmwareCertificates (fw_update_ca, fw_update_ca_key, fw_update_cert, fw_update_cert_key);
135+ }
136+
102137 // Database for persistency
103138 static constexpr const char * DATABASE_NAME = " security_centralsystem.db" ;
104139 if (reset_all)
@@ -207,7 +242,7 @@ int main(int argc, char* argv[])
207242 // Configure for security profile 2 : TLS + HTTP Basic Authentication
208243 std::cout << " [" << chargepoint_id << " ] - Configuring security profile 2" << std::endl;
209244
210- // Load server CA certificate
245+ // Load server CA certificates
211246 Certificate server_ca_certificate (std::filesystem::path (config_p2.stackConfig ().tlsServerCertificateCa ()));
212247
213248 // Get installed certificates
@@ -370,6 +405,55 @@ int main(int argc, char* argv[])
370405 {
371406 std::cout << " [" << chargepoint_id << " ] - Unable to retrieve security logs" << std::endl;
372407 }
408+
409+ // Get installed manufacturer certificates
410+ std::vector<CertificateHashDataType> certificates;
411+ if (chargepoint->getInstalledCertificateIds (CertificateUseEnumType::ManufacturerRootCertificate, certificates))
412+ {
413+ // Delete all installed certificates
414+ std::cout << " [" << chargepoint_id << " ] - " << certificates.size () << " installed CA certificate(s)" << std::endl;
415+ for (const CertificateHashDataType& cert : certificates)
416+ {
417+ if (chargepoint->deleteCertificate (cert) != DeleteCertificateStatusEnumType::Accepted)
418+ {
419+ std::cout << " [" << chargepoint_id << " ] - Unable to delete CA certificate : " << cert.serialNumber .str ()
420+ << std::endl;
421+ }
422+ }
423+ }
424+ else
425+ {
426+ std::cout << " [" << chargepoint_id << " ] - Unable to retrieve the list of installed CA certificates" << std::endl;
427+ }
428+
429+ // Install manufacturer CA certificate
430+ Certificate ca_cert (fw_update_ca);
431+ CertificateStatusEnumType install_status =
432+ chargepoint->installCertificate (CertificateUseEnumType::ManufacturerRootCertificate, ca_cert);
433+ if (install_status == CertificateStatusEnumType::Accepted)
434+ {
435+ // Get the signing certificate and its private key
436+ Certificate signing_cert (fw_update_cert);
437+ PrivateKey signing_cert_key (fw_update_cert_key, PRIVATE_KEYS_PASSPHRASE);
438+
439+ // Sign the "firmware" => use security_chargepoint binary
440+ std::vector<uint8_t > signature_bytes = signing_cert_key.sign (" security_chargepoint" );
441+ std::string signature = base64::encode (&signature_bytes[0 ], signature_bytes.size ());
442+
443+ // Start a signed firmware update
444+ chargepoint->signedUpdateFirmware (1234 ,
445+ " ftp://localhost/security_chargepoint" ,
446+ Optional<unsigned int >(),
447+ DateTime::now (),
448+ Optional<std::chrono::seconds>(),
449+ DateTime::now (),
450+ signing_cert,
451+ signature);
452+ }
453+ else
454+ {
455+ std::cout << " [" << chargepoint_id << " ] - Unable to install the manufacturer certificate" << std::endl;
456+ }
373457 }
374458 break ;
375459
@@ -389,3 +473,59 @@ static bool isConfigurationChangeAccepted(ConfigurationStatus status)
389473{
390474 return ((status == ConfigurationStatus::Accepted) || (status == ConfigurationStatus::RebootRequired));
391475}
476+
477+ /* * @brief Create the certificates for the signed update firmware procedure */
478+ static void createSignedUpdateFirmwareCertificates (std::filesystem::path fw_update_ca,
479+ std::filesystem::path fw_update_ca_key,
480+ std::filesystem::path fw_update_cert,
481+ std::filesystem::path fw_update_cert_key)
482+ {
483+ // CA certificate
484+ PrivateKey ca_key (PrivateKey::Type::EC, PrivateKey::Curve::PRIME256_V1, PRIVATE_KEYS_PASSPHRASE);
485+ ca_key.privateToFile (fw_update_ca_key);
486+
487+ CertificateRequest::Subject ca_subject;
488+ ca_subject.country = " FR" ;
489+ ca_subject.state = " Savoie" ;
490+ ca_subject.location = " Chambery" ;
491+ ca_subject.organization = " Open OCPP" ;
492+ ca_subject.organization_unit = " Examples" ;
493+ ca_subject.common_name = " Signed firmware update CA" ;
494+ ca_subject.
email_address =
" [email protected] " ;
495+
496+ CertificateRequest::Extensions ca_extensions;
497+ ca_extensions.basic_constraints .present = true ;
498+ ca_extensions.basic_constraints .is_ca = true ;
499+ ca_extensions.basic_constraints .path_length = 1u ;
500+ ca_extensions.subject_alternate_names .push_back (" localhost" );
501+ ca_extensions.subject_alternate_names .push_back (" 127.0.0.1" );
502+
503+ CertificateRequest ca_req (ca_subject, ca_extensions, ca_key);
504+
505+ Certificate ca_cert (ca_req, ca_key, Sha2::Type::SHA256, 7300u );
506+ ca_cert.toFile (fw_update_ca);
507+
508+ // Signing certificate
509+ PrivateKey signing_cert_key (PrivateKey::Type::EC, PrivateKey::Curve::PRIME256_V1, PRIVATE_KEYS_PASSPHRASE);
510+ signing_cert_key.privateToFile (fw_update_cert_key);
511+
512+ CertificateRequest::Subject signing_cert_subject;
513+ signing_cert_subject.country = " FR" ;
514+ signing_cert_subject.state = " Savoie" ;
515+ signing_cert_subject.location = " Chambery" ;
516+ signing_cert_subject.organization = " Open OCPP" ;
517+ signing_cert_subject.organization_unit = " Examples" ;
518+ signing_cert_subject.common_name = " Signed firmware update signing certificate" ;
519+ signing_cert_subject.
email_address =
" [email protected] " ;
520+
521+ CertificateRequest::Extensions signing_cert_extensions;
522+ signing_cert_extensions.basic_constraints .present = true ;
523+ signing_cert_extensions.basic_constraints .is_ca = false ;
524+ signing_cert_extensions.subject_alternate_names .push_back (" localhost" );
525+ signing_cert_extensions.subject_alternate_names .push_back (" 127.0.0.1" );
526+
527+ CertificateRequest signing_cert_req (signing_cert_subject, signing_cert_extensions, signing_cert_key);
528+
529+ Certificate signing_cert (signing_cert_req, ca_cert, ca_key, Sha2::Type::SHA256, 7300u );
530+ signing_cert.toFile (fw_update_cert);
531+ }
0 commit comments