All articles

Updated

Your wallbox, your backend? Why migrating a charge point to a new CSMS fails at the security profile

  • ocpp
  • security
  • certificates
  • data-act

A customer buys a wallbox, uses it for two years with the manufacturer's app, and then wants something else. Maybe a tariff optimizer that charges on the cheapest hours, maybe a PV surplus service, maybe just their own home automation that finally has an OCPP backend. So they ask the obvious question: can I point my charge point at a different CSMS?

The regulatory answer is moving towards yes. The technical answer, in far too many cases, is still no. And the thing that decides it is not the app, not the tariff and not the vendor's business model. It is the OCPP security profile the box is running.

What the regulation actually says

The relevant law here is the EU Data Act (Regulation (EU) 2023/2854), whose core provisions apply since September 2025. It covers connected products, and a networked wallbox is exactly that. Users (the people and businesses that own or rent the device) have the right to access the data generated by their use of the product, and to share that data with third parties of their choosing, with minimal legal and technical effort.

That is a genuine shift. The charging data of a privately owned wallbox is no longer something the manufacturer or the contracted backend provider can treat as theirs alone. If the owner wants their sessions, meter values and charging profiles to land in a tariff optimizer or an energy management service, the law is on the owner's side.

But a right to the data is not automatically a right to have the OCPP backend extended with a data export. In practice, the cleanest way to get charging data into a service of your choice is to let that service's CSMS talk to the station directly, so it can also steer the charging and not just read it afterwards. Which brings us to the part the regulation does not describe: what that migration means technically.

What a CSMS migration actually is

In OCPP 2.x, the connection to a backend is described by a NetworkConnectionProfile. It carries the CSMS URL, the transport, a message timeout, the network interface and, importantly, a securityProfile field. A charging station holds several of these connection profiles in numbered configuration slots and tries them in the order given by OCPPCommCtrlr.NetworkConfigurationPriority. The spec requires support for at least two slots (B09.FR.06), so that a station can also be moved remotely.

The standard migration path is use case B10 (Migrate to new CSMS): the current CSMS writes a new connection profile into a free slot with SetNetworkProfileRequest (B09), reorders NetworkConfigurationPriority so the new profile comes first, sends a ResetRequest(OnIdle), and after the reboot the station connects to the new CSMS. If the new connection profile fails after NetworkProfileConnectionAttempts tries, the station falls back to the next entry in the list.

Note who is driving here: the old CSMS. B10 is written for a CPO handing a site over to another CPO in an orderly fashion. The private owner who just wants out has no such actor. Their only lever is whatever the charging station exposes locally, through a web UI, a Bluetooth app or a config file.

And what they need to provide locally depends strongly on the security profile.

The security profiles OCPP 2.x defines

The protocol stack article already introduced the three profiles from the transport side, including why the profile 0 you occasionally hear about is an OCPP 1.6-J legacy setting and not something OCPP 2.x defines. Here they are again, together with the authentication details that can turn from a transport detail into a product problem during a migration:

ProfileCharging station authCSMS authChannel
1HTTP Basic Authenticationnoneplain, no TLS
2HTTP Basic AuthenticationTLS server certificateTLS
3TLS client certificateTLS server certificateTLS

The OCA's Security Operations Guide is even more direct than the spec text: using OCPP 2.x without implementing security profile 2 (and optionally 3) is not a valid OCPP 2.x implementation, and certification for OCPP 2.x requires support for profile 2. So for anything you meet in the field, profile 2 or 3 is the realistic starting point of a migration.

Two generic rules apply to all of them. A station and a CSMS use exactly one profile at a time, and either side terminates the connection if the other tries a different one (A00.FR.001 to A00.FR.003). And the security profile has to be configured before OCPP communication is possible at all (A00.FR.004).

Profile 1: unsecured transport with Basic Authentication

What the user has to change: URL, charge point identity, password. That is it.

The username must equal the charging station identity used in the OCPP-J connection URL (A00.FR.204), and the password lives in the SecurityCtrlr.BasicAuthPassword variable: a random string of 16 to 40 characters, sent as UTF-8, not base64 encoded (A00.FR.205, and note this differs from how OCPP 1.6 did it). Any local UI with three text fields can do this migration.

The catch is that you should not be running profile 1 in the field in the first place. The spec limits it to trusted networks such as a VPN between CSMS and station (A00.FR.201), and the OCA is blunt about the consequence: if the VPN is the only security measure, one misconfiguration or one stolen SIM card exposes the CSMS and potentially every station behind it. So profile 1 is the easy migration you are not supposed to want.

Profile 2: TLS with Basic Authentication

What the user has to change: URL, identity, password, and the trust anchor.

This is where migrations can already start to fail. The station must verify the certification path of the CSMS certificate (A00.FR.308) and verify that the commonName contains the CSMS FQDN (A00.FR.309). If the certificate or the chain is invalid, the station raises an InvalidCsmsCertificate security event and terminates the connection (A00.FR.310, A00.FR.311). The spec even guards the switch itself: if a station is asked to move to a profile of 2 or higher and no valid CSMSRootCertificate is installed, it must reject the request and not change the profile (A05.FR.02).

The obvious question is whether the station just trusts the public CA that issued the new CSMS certificate, the way a browser would. Usually not, and by design. The OCA explicitly recommends against preinstalled well-known root CA bundles on charging stations, because trusting hundreds of CAs in critical infrastructure means an attacker only has to compromise one of them, and the resulting attack hits every charger carrying that bundle. Only roots from the Charge Point Operator hierarchy are supposed to be used for the OCPP connection.

Practically, this means a profile 2 migration succeeds only if one of the following holds:

  • the new CSMS presents a certificate that chains to a root CA the station already trusts (rare across operators, likely only if both use the same public CA and the vendor did ship a bundle),
  • the local UI lets the user install a new root certificate as PEM, or
  • someone with an OCPP connection installs it first with InstallCertificateRequest (use case M05), which means the operator of the old CSMS has to cooperate.

Three more things make this worse in the field. Wildcard certificates are not OCPP compliant, so a new CSMS serving *.example.com will be rejected unless the vendor implemented the non recommended AllowCSMSTLSWildcards opt out. The station and CSMS must agree on TLS 1.2 or higher and on the mandated cipher suites (A00.FR.313, A00.FR.318, A00.FR.319), otherwise you get an InvalidTLSVersion or InvalidTLSCipherSuite event and a closed connection. And the clock has to be right before the first TLS handshake, because a station with a wrong date cannot validate the server certificate at all. The spec calls this out, and the OCA recommends NTS (Network Time Security, RFC 8915, which is NTP with TLS based authentication so nobody can spoof the clock into accepting an expired certificate) and warns that the OCPP Heartbeat cannot serve as the time source, since it only exists after the connection you are trying to establish.

Profile 3: TLS with client side certificates

What the user has to change: everything above, plus a new client certificate issued by the new operator's PKI. In practice, this is where self service migration ends.

The station authenticates with its own certificate as a TLS client certificate (A00.FR.401, A00.FR.402). On the other side, the new CSMS does not just check the chain (A00.FR.403). It also verifies that the organizationName (O) in the subject contains the CSO name (A00.FR.404) and that the commonName (CN) contains the unique serial number of the charging station (A00.FR.405). A certificate issued by the previous operator therefore fails twice over. Wrong chain, wrong organization.

So the box needs a fresh certificate, and OCPP has exactly the mechanism for that. In use case A02 the CSMS triggers the update, the station generates a new key pair and sends a SignCertificateRequest with the CSR, the CSMS forwards it to its CA and returns the signed certificate with CertificateSignedRequest. A03 is the same flow initiated by the station.

Read that sequence again with a migration in mind. Every message in it travels over an established OCPP connection to the CSMS that is supposed to sign the certificate. But the new CSMS will not accept a TLS connection from a station whose client certificate it cannot validate. The enrollment path runs through the door it is meant to unlock. Unless the new operator provides an out of band enrollment route, or the old CSMS is willing to install the new root and the new station certificate on the way out, there is no path from A to B inside OCPP.

The OCA describes the workaround for the manufacturing case, and it is the same shape: let the station first connect to a commissioning server, and let that server swap the certificate for one from the target PKI before the station ever talks to the production CSMS. That is a migration service the new operator has to build. It is not something an owner can do from a settings page.

The two traps that make it worse

You cannot go back down. Lowering the security profile is deliberately not part of OCPP and must not be done with SetVariablesRequest or DataTransfer (A00.FR.005). Worse for a migrating owner: once a station has successfully connected with a higher profile, it must delete every NetworkConnectionProfile with a lower profile and update the priority list accordingly, and the CSMS must refuse lower profile connections from then on (A05.FR.06, A05.FR.07). The old, simple slot you were hoping to reuse is gone.

OCPP 2.1 softened this a little with an AllowSecurityProfileDowngrade variable, and it exists precisely because of CSMS to CSMS migration. But it only permits going from profile 3 to profile 2, never down to profile 1. The consequence for anyone building a receiving CSMS: you must support the profile the station is already using, or at least profile 2.

The root certificate may be cross signed. If SecurityCtrlr.AdditionalRootCertificateCheck is true, only one CSMSRootCertificate (plus a temporary fallback) may be installed, and a new root CA is only accepted if it is signed by the CA it replaces (M05.FR.09 to M05.FR.13). That is a sound anti tampering measure, since an attacker would have to compromise both the CSMS and the CA. It also means a new operator's independent root CA certificate can never be installed over OCPP, because the previous operator's CA would have to sign it. For a cross operator migration on such a station, the OCPP path is closed by design.

Where it breaks in practice

Line up the profiles against what a typical home wallbox actually exposes locally.

ProfileWhat the user must supplyTypical local UI support
1URL, identity, passwordyes, three text fields
2plus new CSMS root certificaterarely, PEM upload is uncommon
3plus CSR generation, signed client certificate, matching O and CNalmost never

Vendor apps and local web UIs often only help at commissioning time, to enter the OCPP URL and credentials. Certificate handling was assumed to be the CPO's business. Done over OCPP, from a backend that cooperates. That assumption does not hold when the person doing the migration is the owner and the old backend has no interest in helping.

The result is a device that is fully capable of speaking to another CSMS, sitting behind a UI that does not support this migration.

What would make this work

For charging station vendors, the local configuration interface needs to grow up. Concretely:

  • URL, charge point identity and Basic Auth password, as today.
  • Install and view a CSMS root certificate as PEM, and list or delete installed certificates (the OCPP equivalents are M03, M04, M05).
  • Generate a key pair and export a CSR, so the user can hand it to the new operator, plus an import for the signed certificate.
  • Show the active security profile and the configured network slots, with the downgrade rules honestly explained instead of a silent rejection.
  • Reliable system time before the first TLS attempt, via NTP or better NTS.
  • Surface the security events. A user staring at a station that will not connect should be told it was InvalidCsmsCertificate, not left with a blinking LED.

For operators of a receiving CSMS, the migration is a product feature, not a support ticket:

  • Publish your root certificate chain and your CSMS FQDN, and do not rely on wildcard certificates.
  • Support profile 2 at minimum (certification requires it anyway), and support the profile the incoming stations already run.
  • Offer an enrollment endpoint that accepts a CSR out of band, or a commissioning server the station can reach before it is fully provisioned.
  • Document which vendors' local UIs can actually complete the steps. Your onboarding funnel dies at whichever step the box cannot perform.

Checking this from the CSMS side

Testing a migration needs a receiving CSMS you control. Before setting one up it is worth splitting the failures above by which side refuses, because the two are not equally observable.

When the CSMS refuses (a client certificate it cannot validate, Basic Auth that does not match, a security profile the station is not provisioned for), it can record what happened. EVSExplorer writes every attempt as a connection event with a reason on it, and pinning a station to a security profile makes connection attempts that do not meet that profile's requirements visible.

# Provision the station for mutual TLS only
curl -s -X PATCH $BASE/api/charge-points/CS001 \
  -H 'Content-Type: application/json' -d '{"securityProfile": 3}'

# Which security profile did recent sessions negotiate, and why was anything refused?
curl -s "$BASE/api/charge-points/CS001/connection-events?limit=10" \
  | jq '.[] | {recordedAt, event, reason, securityProfile}'

Every connection event records the negotiated security profile, so you can tell when a station falls back to a lower one. A refused attempt documents its reason in the same way: profile_mismatch, invalid_client_cert, missing_auth or invalid_auth. If the station is pinned to a different security profile, an already open session is closed with profile_changed so the station reconnects on the security profile it is provisioned for.

One peculiarity: A00.FR.405 requires the commonName to contain the station's serial number. EVSExplorer checks the whole CN against the charge point id. That is server policy, not an OCPP rule.

When the station refuses, the receiving CSMS learns very little. That is exactly the profile 2 case from earlier in this article. The station cannot validate the certificate chain of the new CSMS and therefore aborts the TLS handshake. No WebSocket and no OCPP session come into being, so there is nothing to report anything over.

This failure is not completely silent one layer down, though. A station that cannot validate the chain typically ends the handshake with a TLS unknown_ca alert, which the other end sees even though OCPP never starts. That signal lives in the TLS layer and not in an OCPP message log. Whether you ever get to read it therefore depends on what your CSMS logs about handshakes that abort before the upgrade.

It is tempting to fill that gap with the station's own security events, but that cannot work. The station does store the event in its security log (A04.FR.04) and must queue notifications for guaranteed delivery while offline (A04.FR.02), yet delivery still needs a connection. B02.FR.02 states it: until a BootNotification is answered with Accepted, a station may not send any CALL except BootNotificationRequest unless the CSMS asks for it, and SecurityEventNotification is not a value TriggerMessage can request.

The security events a station reports (InvalidCsmsCertificate, InvalidTLSVersion, InvalidTLSCipherSuite) are therefore a later analysis and not a live signal, and that analysis may not land where you are standing. In the B10 flow the station makes NetworkProfileConnectionAttempts attempts to connect per entry of the priority list (B10.FR.03). Once those are exhausted it should fall back to the connection profile of its last successful connection (B10.FR.07). The queued account of why the new backend turned it away is therefore more likely to be delivered to the old CSMS, provided that one still accepts the station. Which in itself says something about who this process favours.

On the receiving side you are left with connection events for what you refused, and an aborted handshake for what refused you.

The security profile 3 enrollment problem remains. Without an existing WebSocket connection no CSR gets signed. Security events and TLS alerts change nothing about the A02 and A03 chicken and egg.

Conclusion

The Data Act settled the question of who owns the charging data. It did not settle the mechanics, and the mechanics live in a spec that was written on the assumption that a cooperative CPO drives every change. Profile 1 migrations are trivial but insecure. Profile 2 migrations hinge on one PEM file that most wallboxes give the owner no way to install. Profile 3 migrations require a key ceremony between two operators who may be competitors.

That is not a gap in OCPP. Every one of those requirements makes sense on its own security merits. It is a gap in the tooling around it, and it is one that charging station vendors can close by treating certificate management as something the owner of the device is allowed to do.