The original OCPP 1.6 specification said very little about security. Many networks were deployed with plain ws:// connections and nothing but the charger identity in the URL to tell chargers apart, which means anyone who knows an identity can impersonate a charger. The Open Charge Alliance addressed this with a separate document, the security whitepaper "Improved security for OCPP 1.6-J", which back-ports most of the OCPP 2.0.1 security model to 1.6. This part covers what it adds and how to roll it out. It is part 11 of the series.
What the whitepaper adds
- Three security profiles for transport security and charger authentication.
- Certificate management messages to install, list, delete and sign certificates.
- Security events reported with
SecurityEventNotification, and a security log. - Signed firmware updates with
SignedUpdateFirmware, and log retrieval withGetLog. - An
ExtendedTriggerMessageto trigger the new messages. - New configuration keys, including
SecurityProfile,AuthorizationKey,CpoName,CertificateStoreMaxLength,CertificateSignedMaxChainSizeandAdditionalRootCertificateCheck.
These are additional OCPP-J actions on the same connection, not DataTransfer extensions. A charger that implements them advertises it through its configuration keys and documentation; not every charger that claims 1.6 support implements the whitepaper, so check per model.
The three security profiles
| Profile | Transport | Charger authenticates with | CSMS authenticates with |
|---|---|---|---|
| 1: Unsecured Transport with Basic Authentication | ws:// | HTTP Basic auth | Nothing |
| 2: TLS with Basic Authentication | wss:// (TLS) | HTTP Basic auth | Server certificate |
| 3: TLS with Client Side Certificates | wss:// (mutual TLS) | Client certificate | Server certificate |
Profile 1: Basic auth over plain WebSocket
The charger sends an HTTP Basic Authorization header on the WebSocket upgrade request. The username is the charge point identity and the password is the value of the AuthorizationKey configuration key.
GET /ocpp/CP-0001 HTTP/1.1
Host: csms.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Protocol: ocpp1.6
Authorization: Basic Q1AtMDAwMTo3ZjNrOXEyeHc4bTRwMXQ2djVzMA==That stops casual impersonation, but over plain ws:// the password crosses the network in the clear. The whitepaper positions profile 1 for trusted networks only, such as a private APN or VPN. It is a big improvement over identity-only connections, and a reasonable first step on an existing fleet.
Profile 2: TLS with Basic auth
The connection uses TLS, and the charger validates the CSMS server certificate against a Central System root certificate it has installed. The Basic auth header is the same as profile 1, now protected by TLS. The whitepaper requires TLS 1.2 or higher and specifies a set of cipher suites to support; check the edition you are implementing for the exact list. This is the most common target for 1.6 fleets because it only needs a server certificate and a per-charger password.
Profile 3: mutual TLS
The charger presents its own client certificate during the TLS handshake, and the CSMS uses that certificate to authenticate it instead of a password. The whitepaper sets requirements on the certificate contents, including tying the organization name to the CpoName configuration key and the common name to the charger's unique serial number; check the exact field rules in the whitepaper when building your PKI. Profile 3 needs a certificate issuance process for every charger, which the certificate signing messages below support.
Changing the security profile
[2, "csms-sec-701", "ChangeConfiguration", {"key": "AuthorizationKey", "value": "7f3k9q2xw8m4p1t6v5s0"}]
[3, "csms-sec-701", {"status": "Accepted"}]
[2, "csms-sec-702", "ChangeConfiguration", {"key": "SecurityProfile", "value": "1"}]
[3, "csms-sec-702", {"status": "Accepted"}]The usual path is: set AuthorizationKey (it is write-only, so GetConfiguration will not return its value), make sure the CSMS accepts the new password for that charger, then raise SecurityProfile. The charger then reconnects using the new profile. For profile 2 or 3, the Central System root certificate must be installed first (and for profile 3, the charger's own certificate), and the CSMS endpoint the charger connects to must be a wss:// URL. How the URL is changed on 1.6 hardware is often vendor-specific.
The password itself has length and character requirements in the whitepaper. Generate one random password per charger, store it hashed (or in a secret store) on the CSMS side, and never reuse one password across a fleet.
Certificate management messages
| Message | Direction | Purpose |
|---|---|---|
InstallCertificate | CSMS to CP | Install a root certificate; certificateType is CentralSystemRootCertificate or ManufacturerRootCertificate |
GetInstalledCertificateIds | CSMS to CP | List installed root certificates of a type, as certificateHashData |
DeleteCertificate | CSMS to CP | Delete a certificate identified by certificateHashData |
SignCertificate | CP to CSMS | Charger sends a CSR for its client certificate |
CertificateSigned | CSMS to CP | CSMS returns the signed certificate chain |
ExtendedTriggerMessage | CSMS to CP | Trigger messages including SignChargePointCertificate |
certificateHashData identifies a certificate by hashAlgorithm (SHA256, SHA384 or SHA512), issuerNameHash, issuerKeyHash and serialNumber, the same scheme OCPP 2.0.1 uses.
The client certificate flow for profile 3 (and for renewing it) looks like this:
[2, "csms-et-703", "ExtendedTriggerMessage", {"requestedMessage": "SignChargePointCertificate"}]
[3, "csms-et-703", {"status": "Accepted"}]
[2, "sc-1", "SignCertificate", {"csr": "-----BEGIN CERTIFICATE REQUEST-----\nMIIC...\n-----END CERTIFICATE REQUEST-----"}]
[3, "sc-1", {"status": "Accepted"}]
[2, "csms-cs-704", "CertificateSigned", {"certificateChain": "-----BEGIN CERTIFICATE-----\nMIID...\n-----END CERTIFICATE-----"}]
[3, "csms-cs-704", {"status": "Accepted"}]The private key never leaves the charger. The CSMS forwards the CSR to a certificate authority (its own or the CPO's), and sends back the PEM chain. The charger verifies it and starts using it for new connections. Track certificate expiry per charger and renew well ahead of time; an expired client certificate on profile 3 means the charger cannot connect at all.
Security events
[
2,
"se-41",
"SecurityEventNotification",
{
"type": "SettingSystemTime",
"timestamp": "2026-10-26T09:15:03Z",
"techInfo": "Clock adjusted by +94s from BootNotification.conf"
}
]The response is empty. The whitepaper defines a list of event types, including FirmwareUpdated, FailedToAuthenticateAtCentralSystem, CentralSystemFailedToAuthenticate, SettingSystemTime, StartupOfTheDevice, ResetOrReboot, SecurityLogWasCleared, ReconfigurationOfSecurityParameters, MemoryExhaustion, InvalidMessages, AttemptedReplayAttacks, TamperDetectionActivated, InvalidFirmwareSignature, InvalidFirmwareSigningCertificate, InvalidCentralSystemCertificate, InvalidChargePointCertificate, InvalidTLSVersion and InvalidTLSCipherSuite. Some are designated critical and must be sent to the CSMS (queued if offline); the rest only need to be logged locally. Feed them into your alerting: TamperDetectionActivated and repeated authentication failures deserve a human looking at them.
The CSMS also has duties. It should reject connections with wrong passwords or invalid certificates, avoid revealing whether an identity exists, and log failed attempts. Brute-force attempts against Basic auth from the internet are realistic, so rate-limit failed upgrades per identity and per source.
Signed firmware and logs
SignedUpdateFirmware replaces UpdateFirmware (part 10) with a version that carries a signature and the signing certificate, so the charger can verify the image before installing it:
[
2,
"csms-suf-705",
"SignedUpdateFirmware",
{
"requestId": 3301,
"retries": 3,
"retryInterval": 600,
"firmware": {
"location": "https://firmware.example.com/vendorx/dcf60/3.5.0.bin",
"retrieveDateTime": "2026-10-27T02:00:00Z",
"signingCertificate": "-----BEGIN CERTIFICATE-----\nMIID...\n-----END CERTIFICATE-----",
"signature": "MEUCIQDa...base64..."
}
}
]The signing certificate is validated against the ManufacturerRootCertificate installed on the charger, and progress is reported with SignedFirmwareStatusNotification, which, unlike the original message, carries the requestId. It adds statuses such as DownloadScheduled, DownloadPaused, InstallScheduled, InstallRebooting, InstallVerificationFailed, InvalidSignature and SignatureVerified. Similarly, GetLog with logType DiagnosticsLog or SecurityLog replaces GetDiagnostics, reporting progress through LogStatusNotification with a requestId.
A realistic migration path
- Inventory which models support the whitepaper and which profiles they support.
- Move everything that can to profile 1 with unique per-charger passwords. Remove identity-only access.
- Stand up TLS with a certificate chain that every model accepts, test it on the bench, and move to profile 2 in batches.
- Use profile 3 where hardware and your PKI operations can support it, starting with new installations.
- Monitor
SecurityEventNotificationand failed connection attempts from day one.
Key takeaways
- Profile 1 is Basic auth over plain WebSocket, profile 2 adds TLS, profile 3 replaces the password with a client certificate.
- Security profiles can be raised remotely but not lowered: test before you upgrade.
- Certificate signing, security events and signed firmware all carry over almost directly to OCPP 2.0.1.
Previous: Part 10, firmware and diagnostics. Next: Part 12, troubleshooting. For the 2.0.1 security model see OCPP 2.0.1 security.

