Certificate Management - CSMS Developer Guide
Based on OCPP 2.1 Edition 2 Specification (Part 2), Section M (Certificate Management). This guide covers all certificate lifecycle operations (M01–M07), including ISO 15118 Plug & Charge certificate installation and update, certificate retrieval, deletion, CA certificate installation, and OCSP/CRL status checking from the CSMS perspective.
1. Overview
IntroductionThe Certificate Management functional block handles all certificate lifecycle operations between the CSMS and Charging Stations. It supports ISO 15118 Plug & Charge (PnC) with seamless X.509 certificate authentication, TLS certificate management for installing, updating, and deleting root CA certificates, and OCSP/CRL status checking for validating certificate revocation status on behalf of Charging Stations.
CSMS Roles
The CSMS plays two distinct roles depending on the message flow:
| Role | Description | Flows |
|---|---|---|
| Responder | Charging Station sends a request, CSMS responds | M01, M02, M06, M07 |
| Initiator | CSMS sends a request to Charging Station | M03, M04, M05 |
ISO 15118 Plug & Charge
Seamless authentication using X.509 certificates stored in the EV, eliminating the need for RFID cards or other external identification means.
TLS Certificate Management
Installing, updating, and deleting root CA certificates and Charging Station certificates to maintain secure communications.
OCSP/CRL Status Checking
Validating certificate revocation status on behalf of Charging Stations using OCSP responders and Certificate Revocation Lists.
Certificate Lifecycle
Complete management of certificate installation, retrieval, deletion, and status verification across the charging infrastructure.
2. Certificate Types & PKI Structure
ReferenceThe CSMS must understand and manage multiple certificate types that form the PKI trust hierarchy for secure EV charging.
Certificate Types
| Type | Description | Used For |
|---|---|---|
V2GChargingStationCertificate | Certificate of the Charging Station (SECC/EVSE Leaf Certificate in ISO 15118). Used for TLS between EV and Charging Station. | EV-CS TLS |
V2GRootCertificate | Root certificate of the ISO 15118 V2G Root CA. The V2G Charging Station Certificate MUST be derived from this root. | PnC authentication |
MORootCertificate | Root certificate from an eMobility Service Provider. Supports PnC with contracts from providers not derived from V2G root. | PnC authentication |
CSMSRootCertificate | Root certificate used by the Charging Station to validate the CSMS server certificate in TLS. | CS-CSMS TLS |
ManufacturerRootCertificate | Root certificate from the Charging Station manufacturer. Used for signed firmware validation. | Firmware mgmt |
OEMRootCertificate | Root certificate from the car manufacturer (OEM). | PnC authentication |
V2GIntermediateCertificate | Intermediate certificates between V2GChargingStationCertificate and V2GRootCertificate. | EV-CS TLS setup |
PKI Hierarchy
Four PKIs are involved in ISO 15118:
1. CSO (Charging Station Operator)
Trust anchor: V2G Root CA
2. CPS (Certificate Provisioning Service)
Trust anchor: V2G Root CA
3. MO (Mobility Operator)
May operate own Root CA or derive from V2G Root CA
4. OEM (Car Manufacturer)
May operate own Root CA or derive from V2G Root CA
Certificate-to-Use-Case Mapping
| Certificate | Use Cases | Remarks |
|---|---|---|
ChargingStationCertificate | A02, A03 | Used for OCPP security; chain must also be available |
CPS Certificate Chain | M03, M04, M05 | For Plug & Charge authentication |
EVContractCertificate | M01, M02 | Shorter lifetime (for plug & charge) |
MORootCertificate | M03, M04, M05 | For Plug & Charge authentication |
OEMProvisioningCertificate | M01, M02 | Long lifetime, installed in EV by OEM |
V2GChargingStationCertificate | A02, A03 | Chain must be available; retrievable by CS |
V2GRootCertificate | M03, M04, M05 | Only necessary to install for PnC authentication |
V2GIntermediateCertificate | A02, A03, M03, M04 | Between V2GChargingStationCertificate and V2GRootCertificate |
3. Message Direction Summary
Reference| Message | Direction | CSMS Role | Use Case |
|---|---|---|---|
Get15118EVCertificateRequest | CS → CSMS | Respond with Get15118EVCertificateResponse | M01, M02 |
GetInstalledCertificateIdsRequest | CSMS → CS | Send request, handle GetInstalledCertificateIdsResponse | M03 |
DeleteCertificateRequest | CSMS → CS | Send request, handle DeleteCertificateResponse | M04 |
InstallCertificateRequest | CSMS → CS | Send request, handle InstallCertificateResponse | M05 |
GetCertificateStatusRequest | CS → CSMS | Respond with GetCertificateStatusResponse | M06 |
GetCertificateChainStatusRequest | CS → CSMS | Respond with GetCertificateChainStatusResponse | M07 |
SignCertificateRequest | CS → CSMS | Respond with SignCertificateResponse, then send CertificateSignedRequest | A02, A03 |
CertificateSignedRequest | CSMS → CS | Send signed certificate, handle CertificateSignedResponse | A02, A03 |
4. M01 — Certificate Installation EV
CS-Initiated| Use Case ID | M01 |
| Name | Certificate Installation |
| Objective | Install a new certificate from the CSMS in the EV |
| Direction | CS → CSMS (CS initiates) |
| CSMS Role | Responder — receives Get15118EVCertificateRequest, responds with Get15118EVCertificateResponse |
Flow Diagram
EV Charging Station CSMS
| | |
| CertificateInstallReq() | |
|------------------------->| |
| | Get15118EVCertificateReq |
| | (iso15118SchemaVersion, |
| | action=Install, exiReq) |
| |---------------------------->|
| | | Forward to Contract
| | | Certificate Pool(s)
| | |
| | Get15118EVCertificateRes |
| | (status, exiResponse) |
| |<----------------------------|
| CertificateInstallRes() | |
|<-------------------------| |Incoming Request: Get15118EVCertificateRequest
The Charging Station forwards this when an EV initiates certificate installation during an ISO 15118 session.
{
"iso15118SchemaVersion": "string (max 50)",
// REQUIRED - Schema version for the 15118 session between EV and CS.
// Needed for parsing the EXI stream.
"action": "Install | Update",
// REQUIRED - For M01, this will be "Install".
"exiRequest": "string (max 11000)",
// REQUIRED - Raw CertificateInstallationReq from EV, Base64 encoded.
// Min supported length: 11000.
// Configurable via OCPPCommCtrlr.FieldLength
"maximumContractCertificateChains": "integer (>= 0)",
// (2.1) ABSENT during ISO 15118-2 session.
// REQUIRED during ISO 15118-20 session.
// Maximum number of contracts the EV wants to install.
"prioritizedEMAIDs": ["string (max 255)", ...],
// (2.1) ABSENT during ISO 15118-2. OPTIONAL during ISO 15118-20.
// EMAIDs for which contract certificates must be requested first.
// Min: 1, Max: 8 items
}CSMS Response: Get15118EVCertificateResponse
{
"status": "Accepted | Failed",
// REQUIRED - Whether the message was processed properly.
"statusInfo": { // OPTIONAL
"reasonCode": "string (max 20)",
"additionalInfo": "string (max 1024)"
},
"exiResponse": "string (max 17000)",
// REQUIRED - Raw CertificateInstallationRes for the EV, Base64 encoded.
// Min supported length: 17000.
// Configurable via OCPPCommCtrlr.FieldLength
"remainingContracts": "integer (>= 0)"
// (2.1) Number of contracts that can be retrieved with additional
// requests. Used for ISO 15118-20 multi-contract flow.
}CSMS Implementation Logic
HANDLE Get15118EVCertificateRequest(request):
ASSERT request.action == "Install"
// 1. Parse the EXI request
// Use request.iso15118SchemaVersion to determine the correct parser
// 2. Forward to Contract Certificate Pool / secondary actor
// The CSMS is responsible for forwarding the CertificateInstallationRequest
// to the appropriate backend (e.g., contract certificate pool per VDE-AR-E 2802-100-1)
// 3. Determine ISO 15118 version from presence of maximumContractCertificateChains
IF request.maximumContractCertificateChains IS PRESENT:
// ISO 15118-20 session
isISO15118_20 = true
ELSE:
// ISO 15118-2 session
isISO15118_20 = false
// 4. For ISO 15118-20: Handle multi-contract flow
IF isISO15118_20:
// Fetch contracts from all Contract Certificate Pools
// Respect prioritizedEMAIDs ordering if present
// Return first CertificateInstallationRes + total remainingContracts
response.remainingContracts = totalAvailableContracts - 1
// The CS will send additional Get15118EVCertificateRequest messages
// as long as remainingContracts > 0 (see req M01.FR.06)
// Each subsequent response MUST decrease remainingContracts by 1 (req M01.FR.07)
// 5. Build response
response.status = "Accepted" // or "Failed" if processing failed
response.exiResponse = base64EncodedCertificateInstallationRes
RETURN responseRequirements (CSMS-relevant)
| ID | Requirement |
|---|---|
M01.FR.04 | When maximumContractCertificateChains is present AND CSMS has received all CertificateInstallationRes from the certificate pool(s): CSMS SHALL return the first CertificateInstallationRes and total number of available contracts in remainingContracts. |
M01.FR.07 | When ISO 15118-20 AND CS sends another Get15118EVCertificateRequest (because remainingContracts > 0): CSMS SHALL return the next CertificateInstallationRes and decrease remainingContracts by 1. |
Error Handling
- If the CSMS cannot respond in time, the Charging Station SHALL indicate failure to the EV.
- The ISO 15118-2 message timeout for CertificateInstallationReq is 5 seconds.
5. M02 — Certificate Update EV
CS-Initiated| Use Case ID | M02 |
| Name | Certificate Update |
| Objective | Update an existing certificate in the EV via the CSMS |
| Direction | CS → CSMS (CS initiates) |
| CSMS Role | Responder — receives Get15118EVCertificateRequest with action = Update, responds with Get15118EVCertificateResponse |
Flow Diagram
EV Charging Station CSMS
| | |
| CertificateUpdateReq() | | [ISO 15118-2]
| -- OR -- | |
| CertificateInstallReq() | | [ISO 15118-20]
|------------------------->| |
| | Get15118EVCertificateReq |
| | (iso15118SchemaVersion, |
| | action=Update, exiReq) |
| |---------------------------->|
| | | Forward to Contract
| | | Certificate Pool
| | Get15118EVCertificateRes |
| | (status, exiResponse) |
| |<----------------------------|
| CertificateUpdateRes() | |
|<-------------------------| |Shared Message Schemas
The message schemas are identical to M01. The only difference is the action field:
- M01 (Install):
action = "Install" - M02 (Update):
action = "Update"
For ISO 15118-2: The Charging Station sends action = Update upon receiving a CertificateUpdateReq from the EV.
For ISO 15118-20: ISO 15118-20 does not differentiate between Install and Update; the
Charging Station acts according to M01 (req M02.FR.02).
CSMS Implementation Logic
HANDLE Get15118EVCertificateRequest(request):
IF request.action == "Update":
// Forward to the secondary actor (contract certificate pool)
// which will process the CertificateUpdateRequest
// The CSMS is responsible for forwarding it to the appropriate backend
response.status = "Accepted"
response.exiResponse = base64EncodedCertificateUpdateRes
RETURN response
IF request.action == "Install":
// Handle as M01 (see above)Requirements (CSMS-relevant)
| ID | Precondition | Requirement |
|---|---|---|
M02.FR.01 | CS receives ISO 15118 CertificateUpdateReq AND EV uses ISO 15118-2 | CS SHALL forward using Get15118EVCertificateRequest with action = Update. CSMS is responsible for forwarding to secondary actor. |
M02.FR.02 | CS receives ISO 15118 CertificateUpdateReq AND EV uses ISO 15118-20 | CS SHALL act according to M01 (ISO 15118-20 does not differentiate Install/Update). |
Error Handling
- If CSMS cannot respond in time, the Charging Station SHALL indicate failure to the EV.
- The ISO 15118-2 message timeout for CertificateUpdateReq is 5 seconds.
6. M03 — Retrieve Installed Certificates
CSMS-Initiated| Use Case ID | M03 |
| Name | Retrieve list of available certificates from a Charging Station |
| Objective | Enable the CSMS to retrieve a list of installed certificates from a Charging Station |
| Direction | CSMS → CS (CSMS initiates) |
| CSMS Role | Initiator — sends GetInstalledCertificateIdsRequest, handles GetInstalledCertificateIdsResponse |
Flow Diagram
CSMS Charging Station
| |
| GetInstalledCertificateIdsRequest |
| (certificateType) |
|------------------------------------->|
| | Compute hashes and
| | list matching certs
| GetInstalledCertificateIdsResponse |
| (status, certificateHashDataChain) |
|<-------------------------------------|Outgoing Request: GetInstalledCertificateIdsRequest
{
"certificateType": [
"V2GRootCertificate" | "MORootCertificate" | "CSMSRootCertificate" |
"V2GCertificateChain" | "ManufacturerRootCertificate" | "OEMRootCertificate"
]
// OPTIONAL - Types of certificates requested.
// When OMITTED, ALL certificate types are requested.
// Min: 1 item
}Note: There are no required fields. Omitting certificateType requests all certificates.
Incoming Response: GetInstalledCertificateIdsResponse
{
"status": "Accepted | NotFound",
// REQUIRED - Accepted = matching certificates found.
// NotFound = no matching certificates.
"statusInfo": { // OPTIONAL
"reasonCode": "string (max 20)",
"additionalInfo": "string (max 1024)"
},
"certificateHashDataChain": [ // OPTIONAL (present when status = Accepted)
{
"certificateType": "V2GRootCertificate | MORootCertificate | ...",
// REQUIRED
"certificateHashData": { // REQUIRED - CertificateHashDataType
"hashAlgorithm": "SHA256 | SHA384 | SHA512",
"issuerNameHash": "string (max 128)",
"issuerKeyHash": "string (max 128)",
"serialNumber": "string (max 40)"
},
"childCertificateHashData": [ // OPTIONAL - Max 4 items
{ // Sub-CAs under a root
"hashAlgorithm": "SHA256 | SHA384 | SHA512",
"issuerNameHash": "string (max 128)",
"issuerKeyHash": "string (max 128)",
"serialNumber": "string (max 40)"
}
]
}
]
}CSMS Implementation Logic
FUNCTION retrieveInstalledCertificates(chargingStationId, certificateTypes):
// 1. Build the request
request = new GetInstalledCertificateIdsRequest()
IF certificateTypes IS NOT EMPTY:
request.certificateType = certificateTypes
// If certificateTypes is empty/null, omit the field to get ALL types
// 2. Send to Charging Station
response = sendToChargingStation(chargingStationId, request)
// 3. Handle response
IF response.status == "Accepted":
FOR EACH chain IN response.certificateHashDataChain:
// Store certificate hash data for later use
// (e.g., for DeleteCertificateRequest)
storeCertificateInfo(
chargingStationId,
chain.certificateType,
chain.certificateHashData,
chain.childCertificateHashData // may be null
)
ELSE IF response.status == "NotFound":
// No matching certificates found on the Charging Station
log("No certificates of requested type found on station " + chargingStationId)
RETURN responseRequirements (CSMS-relevant)
| ID | Requirement |
|---|---|
M03.FR.02 | If no certificates matching certificateType are found, CS responds with status = NotFound. |
M03.FR.03 | If matching certificates found, CS responds with status = Accepted. |
M03.FR.04 | CS SHALL include hash data for each matching installed certificate. |
M03.FR.05 | When certificateType = V2GCertificateChain, CS SHALL include hash data for all certificates in the chain. Sub-CAs SHALL be placed as childCertificateHashData under the V2G Charging Station certificate. |
Important Notes
- For installing the V2G Charging Station Certificate, use A02/A03 (not M03). The V2G certificate chain SHOULD NOT include the V2GRootCertificate; install roots using M05.
- Use the returned hash data to identify certificates for deletion (M04).
7. M04 — Delete Certificate
CSMS-Initiated| Use Case ID | M04 |
| Name | Delete a specific certificate from a Charging Station |
| Objective | Enable the CSMS to request the Charging Station to delete an installed certificate |
| Direction | CSMS → CS (CSMS initiates) |
| CSMS Role | Initiator — sends DeleteCertificateRequest, handles DeleteCertificateResponse |
Flow Diagram
CSMS Charging Station
| |
| DeleteCertificateRequest |
| (certificateHashData) |
|------------------------------------->|
| | Attempt to find
| | and delete cert
| DeleteCertificateResponse |
| (status) |
|<-------------------------------------|Outgoing Request: DeleteCertificateRequest
{
"certificateHashData": { // REQUIRED - CertificateHashDataType
"hashAlgorithm": "SHA256 | SHA384 | SHA512",
// REQUIRED - CSMS MUST use the SAME hashAlgorithm that the CS uses
// to report the certificate in GetInstalledCertificateIdsResponse
// (req M04.FR.07)
"issuerNameHash": "string (max 128)",
// REQUIRED - Hash of the issuer's distinguished name (DN),
// calculated over the DER encoding of the issuer's name field.
"issuerKeyHash": "string (max 128)",
// REQUIRED - Hash of the DER encoded public key (value only,
// excluding tag and length) of the subject public key field
// in the issuer's certificate.
"serialNumber": "string (max 40)"
// REQUIRED - Hex string of the serial number,
// without '0x' prefix and without leading zeroes.
}
}Incoming Response: DeleteCertificateResponse
{
"status": "Accepted | Failed | NotFound",
// REQUIRED - Result of the delete operation.
"statusInfo": { // OPTIONAL
"reasonCode": "string (max 20)",
"additionalInfo": "string (max 1024)"
}
}CSMS Implementation Logic
FUNCTION deleteCertificate(chargingStationId, certificateHashData):
// IMPORTANT: Before deleting, the CSMS SHOULD verify:
// 1. DO NOT delete the Charging Station Certificate via this message.
// Deletion of the Charging Station Certificate is NOT allowed via
// DeleteCertificateRequest (req M04.FR.06). The CS will respond with Failed.
// 2. Be VERY careful deleting the last/all CSMSRootCertificates.
// If all CSMSRootCertificates are deleted, the CS will NOT be able to
// connect to any CSMS (cannot validate server certificate).
// ADVISED: Confirm this is truly intended before proceeding.
// 3. Use the SAME hashAlgorithm the CS reported in
// GetInstalledCertificateIdsResponse (req M04.FR.07)
request = new DeleteCertificateRequest()
request.certificateHashData = certificateHashData
response = sendToChargingStation(chargingStationId, request)
SWITCH response.status:
CASE "Accepted":
// Certificate was successfully deleted
// Note: If deleted cert was a sub-CA or root, the CS MAY also
// delete all child certificates (req M04.FR.08)
removeCertificateFromLocalStore(chargingStationId, certificateHashData)
CASE "Failed":
// Deletion failed. Possible reasons:
// - Certificate is the Charging Station Certificate (not deletable)
// - CS rejected deletion (last one of its type)
// - Internal CS error
log("Delete failed: " + response.statusInfo?.reasonCode)
CASE "NotFound":
// Certificate not found on the Charging Station
log("Certificate not found on station " + chargingStationId)
RETURN responseRequirements (CSMS-relevant)
| ID | Precondition | Requirement |
|---|---|---|
M04.FR.02 | Certificate found | CS responds status = Accepted. |
M04.FR.03 | Deletion fails or CS rejects | CS responds status = Failed. A CS MAY reject to prevent deleting the last one of its type. |
M04.FR.04 | Certificate not found | CS responds status = NotFound. |
M04.FR.06 | certificateHashData refers to the Charging Station Certificate | CS SHALL respond status = Failed. CSMS must NOT attempt to delete the CS certificate this way. |
M04.FR.07 | When deleting a certificate | CSMS SHALL use the same hashAlgorithm as the CS uses to report the certificate in GetInstalledCertificateIdsResponse. |
M04.FR.08 | Deleted cert is a sub-CA or root | CS MAY also delete all child certificates. |
Warnings
- Deleting all
ManufacturerRootCertificatesprevents "Signed Firmware" from being installed. - Deleting all
CSMSRootCertificateswill sever the CS's ability to connect to any CSMS. - Always run M03 first to retrieve current certificates and their hash data before attempting deletion.
8. M05 — Install CA Certificate
CSMS-Initiated| Use Case ID | M05 |
| Name | Install CA certificate in a Charging Station |
| Objective | Install a new CSMS root, MO root, Manufacturer root, or V2G root certificate on the Charging Station |
| Direction | CSMS → CS (CSMS initiates) |
| CSMS Role | Initiator — sends InstallCertificateRequest, handles InstallCertificateResponse |
Flow Diagram
CSMS Charging Station
| |
| InstallCertificateRequest |
| (certificateType, certificate) |
|------------------------------------->|
| | Attempt to install
| | certificate in trust store
| InstallCertificateResponse |
| (status) |
|<-------------------------------------|Outgoing Request: InstallCertificateRequest
{
"certificateType": "V2GRootCertificate | MORootCertificate |
ManufacturerRootCertificate | CSMSRootCertificate | OEMRootCertificate",
// REQUIRED - Type of certificate being installed.
"certificate": "string (max 10000)"
// REQUIRED - PEM encoded X.509 certificate.
}Incoming Response: InstallCertificateResponse
{
"status": "Accepted | Rejected | Failed",
// REQUIRED - Result of the installation.
"statusInfo": { // OPTIONAL
"reasonCode": "string (max 20)",
"additionalInfo": "string (max 1024)"
}
}CSMS Implementation Logic
FUNCTION installCACertificate(chargingStationId, certificateType, pemCertificate):
request = new InstallCertificateRequest()
request.certificateType = certificateType
request.certificate = pemCertificate
response = sendToChargingStation(chargingStationId, request)
SWITCH response.status:
CASE "Accepted":
// Certificate successfully installed in the CS trust store
// If it was already present, CS replaces it (req M05.FR.17)
storeCertificateRecord(chargingStationId, certificateType, pemCertificate)
CASE "Rejected":
// Installation rejected. Possible reasons:
// - CertificateEntries.maxLimit would be exceeded (req M05.FR.06)
// - Certificate is invalid (req M05.FR.07)
// - For CSMSRootCertificate with AdditionalRootCertificateCheck=true:
// new cert is NOT signed by the old CSMS Root (req M05.FR.11)
log("Install rejected: " + response.statusInfo?.reasonCode)
CASE "Failed":
// Installation failed due to internal CS error
log("Install failed: " + response.statusInfo?.reasonCode)
RETURN responseCSMS Root Certificate Rotation (Special Logic)
When AdditionalRootCertificateCheck is true on the Charging Station, special rules apply for CSMSRootCertificate installation:
FUNCTION rotateCSMSRootCertificate(chargingStationId, newCertPEM):
// req M05.FR.09: Only one CSMSRootCertificate can be installed at a time
// (plus a temporary fallback)
// req M05.FR.10: The new CSMS Root certificate SHALL replace the old one
// AND the new Root Certificate MUST be signed by the old Root Certificate
// req M05.FR.11: If NOT signed by old root -> CS responds Rejected
// req M05.FR.12: If signed by old root -> CS installs new cert AND
// temporarily keeps old cert as fallback, responds Accepted
// req M05.FR.13: After CS successfully reconnects using the new cert ->
// CS removes the old (fallback) certificate
// req M05.FR.14: If CS cannot verify CSMS server cert with new root ->
// CS tries the old (fallback) root certificate
response = installCACertificate(chargingStationId, "CSMSRootCertificate", newCertPEM)
IF response.status == "Accepted":
// The CS now has both old and new CSMS root certs temporarily
// On next successful TLS connection with new cert, old is removed
// CSMS should ensure its server certificate is signed by the new rootRequirements (CSMS-relevant)
| ID | Precondition | Requirement |
|---|---|---|
M05.FR.02 | Installation successful | CS responds status = Accepted. |
M05.FR.03 | Installation failed | CS responds status = Failed. |
M05.FR.06 | CertificateEntries.maxLimit exceeded | CS responds status = Rejected. |
M05.FR.07 | Certificate is invalid | CS responds status = Rejected. |
M05.FR.09 | AdditionalRootCertificateCheck = true | Only one CSMSRootCertificate (plus temp fallback) allowed at a time. |
M05.FR.10 | AdditionalRootCertificateCheck = true, installing CSMSRootCertificate | New cert SHALL replace old; new cert MUST be signed by old root. |
M05.FR.11 | New cert NOT signed by old root | CS SHALL NOT install; responds status = Rejected. |
M05.FR.12 | New cert IS signed by old root | CS installs new, keeps old as fallback; responds status = Accepted. |
M05.FR.17 | Certificate already present in trust store | CS SHALL replace and respond status = Accepted. |
Important Notes
- This message is for ROOT/CA certificates only. Do NOT use it for
Charging Station leaf certificates. For that, use
CertificateSignedRequest(use cases A02/A03). - Multiple certificates of the same type are allowed.
- The V2G certificate chain SHOULD NOT include the V2GRootCertificate when installed via A02/A03; install roots using this use case (M05).
9. M06 — Get V2G Charging Station Certificate Status
CS-Initiated| Use Case ID | M06 |
| Name | Get V2G Charging Station Certificate status |
| Objective | Enable a Charging Station to cache the OCSP certificate status needed for the TLS handshake between EV and Charging Station |
| Direction | CS → CSMS (CS initiates) |
| CSMS Role | Responder — receives GetCertificateStatusRequest, responds with GetCertificateStatusResponse |
Flow Diagram
Charging Station CSMS
| |
| GetCertificateStatusRequest |
| (ocspRequestData) |
|------------------------------>|
| | Retrieve OCSP certificate
| | status from OCSP responder
| GetCertificateStatusResponse |
| (status, ocspResult) |
|<------------------------------|
| |
| Cache retrieved information |
|<--- |Incoming Request: GetCertificateStatusRequest
{
"ocspRequestData": { // REQUIRED - OCSPRequestDataType
"hashAlgorithm": "SHA256 | SHA384 | SHA512",
// REQUIRED
"issuerNameHash": "string (max 128)",
// REQUIRED - Hash of the issuer's distinguished name (DN), DER encoded.
"issuerKeyHash": "string (max 128)",
// REQUIRED - Hash of the DER encoded public key of the issuer.
"serialNumber": "string (max 40)",
// REQUIRED - Hex serial number without '0x' prefix or leading zeroes.
"responderURL": "string (max 2000)"
// REQUIRED - OCSP responder URL (case insensitive).
// REQUIRED in OCPP (optional in ISO 15118).
}
}CSMS Response: GetCertificateStatusResponse
{
"status": "Accepted | Failed",
// REQUIRED - Whether the CSMS was successful in retrieving the OCSP status.
// Does NOT indicate the validity of the certificate itself.
"statusInfo": { // OPTIONAL
"reasonCode": "string (max 20)",
"additionalInfo": "string (max 1024)"
},
"ocspResult": "string (max 18000)"
// OCSPResponse class per IETF RFC 6960, DER encoded then Base64 encoded.
// MAY only be omitted when status is not Accepted.
// Min supported length: 18000.
// Configurable via OCPPCommCtrlr.FieldLength
}CSMS Implementation Logic
HANDLE GetCertificateStatusRequest(request):
ocspData = request.ocspRequestData
// 1. Build OCSP request per RFC 6960 using the provided hash data
ocspRequest = buildOCSPRequest(
hashAlgorithm: ocspData.hashAlgorithm,
issuerNameHash: ocspData.issuerNameHash,
issuerKeyHash: ocspData.issuerKeyHash,
serialNumber: ocspData.serialNumber
)
// 2. Send OCSP request to the responder URL
TRY:
ocspResponse = httpPost(ocspData.responderURL, ocspRequest)
// 3. Format response per requirements:
// - OCSPResponse per IETF RFC 6960 (req M06.FR.08)
// - Formatted according to ASN.1 [X.680] (req M06.FR.08)
// - DER encoded (req M06.FR.09)
// - Then Base64 encoded for transmission
derEncoded = ocspResponse.toDER()
base64Result = base64Encode(derEncoded)
response.status = "Accepted" // req M06.FR.02
response.ocspResult = base64Result // req M06.FR.03
CATCH error:
// OCSP retrieval failed
response.status = "Failed" // req M06.FR.04
response.statusInfo = {
reasonCode: "OCSPFetchFailed",
additionalInfo: error.message
}
// ocspResult MAY be omitted when status != Accepted
RETURN responseRequirements (CSMS-relevant)
| ID | Requirement |
|---|---|
M06.FR.01 | CSMS SHALL respond with GetCertificateStatusResponse. |
M06.FR.02 | If OCSP retrieval successful: set status = Accepted. |
M06.FR.03 | Include OCSP response data in ocspResult field. |
M06.FR.04 | If OCSP retrieval failed: set status = Failed. |
M06.FR.08 | Format OCSP response data per IETF RFC 6960, formatted according to ASN.1 [X.680]. |
M06.FR.09 | OCSPResponse data SHALL be DER encoded. |
Important Notes
- The
statusfield indicates whether the CSMS retrieved the OCSP status successfully. It does NOT indicate the validity of the certificate itself. - OCPP allows only one certificate per GetCertificateStatusRequest. One request needs to be sent per SubCA certificate.
responderURLis required in OCPP (while optional in ISO 15118). A certificate without a responderURL cannot be checked via this use case.- The Charging Station SHOULD refresh cached OCSP data at least once a week (req M06.FR.10).
- After a Charging Station Certificate update, the CS SHALL refresh OCSP data for the new certificate and intermediates (req M06.FR.07).
10. M07 — Get Vehicle Certificate Chain Revocation Status
CS-Initiated New in 2.1| Use Case ID | M07 |
| Name | Get Vehicle Certificate Chain Revocation Status |
| Objective | Let the Charging Station check validity of the vehicle certificate chain using OCSP and CRL |
| Direction | CS → CSMS (CS initiates) |
| CSMS Role | Responder — receives GetCertificateChainStatusRequest, responds with GetCertificateChainStatusResponse |
New in OCPP 2.1. Required by ISO 15118-20 during the TLS handshake. Results are allowed to be cached at CSMS or Charging Station for at most one week.
Flow Diagram
Charging Station CSMS
| |
| GetCertificateChainStatusRequest |
| (certificateStatusRequests: [ |
| { certHashData, source:OCSP, urls }, |
| { certHashData, source:CRL, urls } |
| ]) |
|---------------------------------------->|
| | For each certificate:
| | 1. Check cached status
| | 2. If not cached, issue
| | OCSP request or download CRL
| GetCertificateChainStatusResponse |
| (certificateStatus: [ |
| { certHashData, source, status, |
| nextUpdate }, |
| ... |
| ]) |
|<-----------------------------------------|
| |
| Cache status for up to 1 week |Incoming Request: GetCertificateChainStatusRequest
{
"certificateStatusRequests": [ // REQUIRED - Min: 1, Max: 4
{
"certificateHashData": { // REQUIRED - CertificateHashDataType
"hashAlgorithm": "SHA256 | SHA384 | SHA512",
"issuerNameHash": "string (max 128)",
"issuerKeyHash": "string (max 128)",
"serialNumber": "string (max 40)"
},
"source": "CRL | OCSP",
// REQUIRED - Whether to check via OCSP or CRL.
"urls": ["string (max 2000)", ...]
// REQUIRED - URL(s) of the OCSP responder or CRL distribution point.
// Min: 1, Max: 5
}
]
}CSMS Response: GetCertificateChainStatusResponse
{
"certificateStatus": [ // REQUIRED - Min: 1, Max: 4
{
"certificateHashData": { // REQUIRED - echo back
"hashAlgorithm": "SHA256 | SHA384 | SHA512",
"issuerNameHash": "string (max 128)",
"issuerKeyHash": "string (max 128)",
"serialNumber": "string (max 40)"
},
"source": "CRL | OCSP",
// REQUIRED - Source used for this status check.
"status": "Good | Revoked | Unknown | Failed",
// REQUIRED - Revocation status of the certificate.
"nextUpdate": "date-time (ISO 8601)"
// REQUIRED - When the status information will next be updated.
}
]
}CSMS Implementation Logic
HANDLE GetCertificateChainStatusRequest(request):
results = []
FOR EACH entry IN request.certificateStatusRequests:
certHash = entry.certificateHashData
source = entry.source
urls = entry.urls
// 1. Check local cache first
cached = checkCache(certHash, source)
IF cached IS NOT NULL AND cached.nextUpdate > now():
results.add(cached)
CONTINUE
// 2. Not cached or expired - perform live check
IF source == "OCSP":
// req M07.FR.01: Perform OCSP request to one of the URLs
result = performOCSPCheck(certHash, urls)
IF result.success:
// req M07.FR.03: Use the OCSP status (Good/Revoked/Unknown)
results.add({
certificateHashData: certHash,
source: "OCSP",
status: result.ocspStatus,
nextUpdate: result.nextUpdate
})
ELSE:
// req M07.FR.02: OCSP request failed
results.add({
certificateHashData: certHash,
source: "OCSP",
status: "Failed",
nextUpdate: now() + 1hour
})
ELSE IF source == "CRL":
// req M07.FR.04: Retrieve CRL from one of the URLs
crl = downloadCRL(urls)
IF crl IS NULL:
// req M07.FR.05: CRL download failed
results.add({
certificateHashData: certHash,
source: "CRL",
status: "Failed",
nextUpdate: now() + 1hour
})
ELSE:
IF crl.contains(certHash.serialNumber):
// req M07.FR.06: Certificate is revoked
results.add({
certificateHashData: certHash,
source: "CRL",
status: "Revoked",
nextUpdate: crl.nextUpdate
})
ELSE:
// req M07.FR.07: Certificate not in CRL -> Good
results.add({
certificateHashData: certHash,
source: "CRL",
status: "Good",
nextUpdate: crl.nextUpdate
})
// Cache the result
cacheResult(certHash, source, results.last())
// req M07.FR.08: Respond with all results
response.certificateStatus = results
RETURN responseExample Request/Response
{
"certificateStatusRequests": [
{
"certificateHashData": {
"hashAlgorithm": "SHA256",
"issuerNameHash": "12345ABCDE",
"issuerKeyHash": "ABCDE1234",
"serialNumber": "AB123456789"
},
"source": "OCSP",
"urls": ["https://ocsp.responder.org/revoked.ocsp"]
},
{
"certificateHashData": {
"hashAlgorithm": "SHA256",
"issuerNameHash": "ABCDE12345",
"issuerKeyHash": "1234ABCDE",
"serialNumber": "987634294239"
},
"source": "CRL",
"urls": [
"https://crls.com/revoked.crl",
"ftp://ftp.crls.com/revoked.crl"
]
}
]
}{
"certificateStatus": [
{
"certificateHashData": {
"hashAlgorithm": "SHA256",
"issuerNameHash": "12345ABCDE",
"issuerKeyHash": "ABCDE1234",
"serialNumber": "AB123456789"
},
"source": "OCSP",
"status": "Good",
"nextUpdate": "2025-02-01T12:00Z"
},
{
"certificateHashData": {
"hashAlgorithm": "SHA256",
"issuerNameHash": "ABCDE12345",
"issuerKeyHash": "1234ABCDE",
"serialNumber": "987634294239"
},
"source": "CRL",
"status": "Good",
"nextUpdate": "2025-02-01T12:00Z"
}
]
}Requirements (CSMS-relevant)
| ID | Precondition | Requirement |
|---|---|---|
M07.FR.01 | source = OCSP | CSMS SHALL perform OCSP request to one of the urls for certificateHashData of each certificate. |
M07.FR.02 | OCSP request fails | CSMS SHALL use status = Failed for this certificate. |
M07.FR.03 | OCSP request succeeds | CSMS SHALL use the OCSP status (Good/Revoked/Unknown) for status. |
M07.FR.04 | source = CRL | CSMS SHALL retrieve CRL from one of the urls for certificateHashData of each certificate. |
M07.FR.05 | CRL download fails | CSMS SHALL use status = Failed for this certificate. |
M07.FR.06 | CRL downloaded AND serialNumber IS in the CRL | CSMS SHALL use status = Revoked. |
M07.FR.07 | CRL downloaded AND serialNumber is NOT in the CRL | CSMS SHALL use status = Good. |
M07.FR.08 | All certificates checked | CSMS SHALL respond with GetCertificateChainStatusResponse containing all results with certificateHashData, source, status, and nextUpdate. |
11. Shared Data Types Reference
ReferenceStatusInfoType
Used in many responses to provide additional status details.
{
"reasonCode": "string (max 20)",
// REQUIRED - Predefined code for the reason. Case-insensitive.
"additionalInfo": "string (max 1024)"
// OPTIONAL - Free-text additional information.
}CertificateHashDataType
Used to uniquely identify a certificate by its issuer's hash data and serial number.
{
"hashAlgorithm": "SHA256 | SHA384 | SHA512",
// REQUIRED
"issuerNameHash": "string (max 128)",
// REQUIRED - Hash of the issuer's distinguished name (DN),
// calculated over the DER encoding of the issuer's name field
// in the certificate being checked.
"issuerKeyHash": "string (max 128)",
// REQUIRED - Hash of the DER encoded public key: the value
// (excluding tag and length) of the subject public key field
// in the issuer's certificate.
"serialNumber": "string (max 40)"
// REQUIRED - Hex string representation of the serial number
// without '0x' prefix and without leading zeroes.
}CustomDataType
Optional extension point for vendor-specific data. Present in all messages.
{
"vendorId": "string (max 255)"
// REQUIRED
}Enum Reference
| Enum | Values | Used In |
|---|---|---|
CertificateActionEnum | Install, Update | Get15118EVCertificateRequest |
Iso15118EVCertificateStatusEnum | Accepted, Failed | Get15118EVCertificateResponse |
GetCertificateIdUseEnum | V2GRootCertificate, MORootCertificate, CSMSRootCertificate, V2GCertificateChain, ManufacturerRootCertificate, OEMRootCertificate | GetInstalledCertificateIdsRequest/Response |
GetInstalledCertificateStatusEnum | Accepted, NotFound | GetInstalledCertificateIdsResponse |
DeleteCertificateStatusEnum | Accepted, Failed, NotFound | DeleteCertificateResponse |
InstallCertificateUseEnum | V2GRootCertificate, MORootCertificate, ManufacturerRootCertificate, CSMSRootCertificate, OEMRootCertificate | InstallCertificateRequest |
InstallCertificateStatusEnum | Accepted, Rejected, Failed | InstallCertificateResponse |
GetCertificateStatusEnum | Accepted, Failed | GetCertificateStatusResponse |
HashAlgorithmEnum | SHA256, SHA384, SHA512 | Multiple messages |
CertificateSigningUseEnum | ChargingStationCertificate, V2GCertificate, V2G20Certificate | SignCertificateRequest, CertificateSignedRequest |
GenericStatusEnum | Accepted, Rejected | SignCertificateResponse |
CertificateSignedStatusEnum | Accepted, Rejected | CertificateSignedResponse |
CertificateStatusSourceEnum | CRL, OCSP | GetCertificateChainStatusRequest/Response |
CertificateStatusEnum | Good, Revoked, Unknown, Failed | GetCertificateChainStatusResponse |
12. Configuration Variables
Reference| Variable | Description | Relevant To |
|---|---|---|
OCPPCommCtrlr.FieldLength["Get15118EVCertificateRequest.exiRequest"] | Max supported length for exiRequest if > 11000 | M01, M02 |
OCPPCommCtrlr.FieldLength["Get15118EVCertificateResponse.exiResponse"] | Max supported length for exiResponse if > 17000 | M01, M02 |
OCPPCommCtrlr.FieldLength["GetCertificateStatusResponse.ocspResult"] | Max supported length for ocspResult if > 18000 | M06 |
MaxCertificateChainSize | Limits the maximum size of the certificateChain field in CertificateSignedRequest | A02, A03 |
CertificateEntries.maxLimit | Maximum number of certificates that can be stored on the Charging Station | M05 |
AdditionalRootCertificateCheck | When true, enforces that new CSMS Root cert must be signed by old one | M05 |