Skip to content

Commit 6b81a44

Browse files
committed
[examples] Added signed firmware update request to security central system when a charge point is connected with security level = 3
1 parent ea50edb commit 6b81a44

File tree

1 file changed

+141
-1
lines changed

1 file changed

+141
-1
lines changed

examples/security_centralsystem/main.cpp

Lines changed: 141 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,15 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2222
SOFTWARE.
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;
3943
using namespace ocpp::types;
4044
using 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 */
4351
static 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 */
4660
int 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

Comments
 (0)