Open Charging Technology · Whitepapers

White Paper

Secure Name Resolution for OCPP

This white paper offers a technical guide for configuring electric vehicle (EV) charging stations compliant with Open Charge Point Protocol (OCPP) v1.6 (+ Security Whitepaper Edition 3+) and OCPP v2.x to resolve domain names securely. Almost every connection a charging station makes starts with a Domain Name System (DNS) query, and classical DNS over UDP port 53 is neither authenticated nor confidential. The paper describes:

The paper also includes operational guidance for firewalls, private APNs and CPO-operated resolvers, and concludes with test criteria for validating an implementation. All statements about the reference implementation refer to the open source C# implementation in WWCP_Node and Vanaheimr Hermod, which runs on charging stations, OCPP Local Controllers, energy meters and vehicles alike.

1. Introduction

A charging station resolves names all the time: the WebSocket URL of its Charging Station Management System (CSMS), the NTS-KE servers of its legal time source (see Secure Time Synchronization for OCPP), the URLs of firmware updates and diagnostics uploads, OCSP responders and CRL distribution points, payment and web portal URLs, and the hosts of vendor specific services. Classical DNS sends these questions in clear text over UDP port 53 and accepts the first answer that matches the query id and port. An attacker on the path — in a mobile network, behind a misconfigured APN, on a shared site network, or on any router between the station and its resolver — can therefore read and forge every answer.

TLS protects the content of most of these connections, so a forged answer does not automatically lead to a forged CSMS. The remaining risks are nevertheless substantial:

Regulations reflect this. The cybersecurity requirements of the EU Radio Equipment Directive (RED) and its harmonised standard EN 18031, and the upcoming EU Cyber Resilience Act (CRA), ask for protection of network communication and for resilience against denial of service. Name resolution is part of that communication, even though it is rarely listed explicitly.

This paper therefore treats the name servers of a charging station like any other security critical backend: they are configured explicitly, reached over an encrypted transport, authenticated by their certificates, and every change of their configuration or their certificates is logged. Because CPOs manage their fleets via OCPP, all of this must be configurable via OCPP as well.

2. Secure DNS Process Flow

2.1 Transports

Transport Standard Default Port Encrypted Notes
UDP RFC 1035 53 no Classical DNS. Must not be used for security relevant names unless the network path is trusted.
TCP RFC 7766 53 no Same security as UDP, but without truncation and fragmentation issues.
TLS RFC 7858 853 yes DNS-over-TLS (DoT). Recommended default for charging stations: a dedicated port is easy to allow in firewalls.
HTTPS RFC 8484 443 yes DNS-over-HTTPS (DoH) using POST and application/dns-message. Useful where only port 443 is reachable.
HTTPS_GET RFC 8484 §4.1 443 yes DoH using GET with a base64url encoded query.
HTTPS_JSON (proprietary) 443 yes The JSON APIs of some public resolvers (application/dns-json). Not standardized, should only be used for diagnostics.

DNS-over-QUIC (RFC 9250) is out of scope of this version of the paper. HTTPS_JSON should not be offered via OCPP. The reference implementation also knows unencrypted HTTP variants of DoH, which exist for tests, and HTTPS_Binary, a second name for HTTPS; neither should be offered via OCPP either.

Encrypted connections are kept open between queries (RFC 7858 §3.4, RFC 7828), so the TLS handshake — and the certificate validation described below — happens once per connection, not once per query.

2.2 Usage Profile

RFC 8310 distinguishes an opportunistic profile, which falls back to unauthenticated or clear text DNS when the encrypted resolver cannot be authenticated, from a strict profile, which does not. Charging stations shall use the strict profile: a name server reached over TLS or HTTPS whose certificate is refused is not used, and the station never silently falls back to UDP. A downgrade that an attacker can trigger by blocking port 853 is no protection at all.

2.3 Server Authentication

At every TLS handshake with an encrypted name server, the charging station asks three questions, in this order. A no to any of them ends the handshake.

  1. Is the certificate issued for the server? The certificate must be issued for the name or the IP address the server is dialled at. This check is never relaxed, neither by a pin nor by any other configuration option: a certificate for another host is a certificate for another host. When a name server is configured by its IP address, its certificate therefore needs an IP address Subject Alternative Name. Many public DoT resolvers have one; CPO-operated resolvers must be issued one.

  2. Does its chain end at a trusted root? Either at a root CA of the operating system, or at a root CA that was installed specifically for name servers (see NameServerRootCertificate in section 3.1.3), or at a root CA the server is pinned to (see below) that is known to the station. Root CAs installed for other purposes, e.g. for NTS-KE servers or for the CSMS, do not vouch for name servers. On most systems the root CAs of the operating system are the complete Web PKI bundle, i.e. the overly broad trust of section 1, so a server whose chain ends there should be held to root pins (section 4.3). (Reference implementation: a root CA of the station's own store that was installed without a purpose vouches for every purpose, name servers included.)

  3. Is it a certificate, and a root, the server is held to? Each server can be held to

    • one or more certificate pins: SHA-256 fingerprints of the DER encoded server certificates it may show, e.g. the current one and an announced successor, and/or
    • one or more root pins: SHA-256 fingerprints of the DER encoded root CA certificates its chain may end at, e.g. the current root CA and its announced successor.

    A pin only ever narrows what is accepted. A pinned certificate that chains to no trusted root is still refused. Fingerprints are taken over the whole certificate, which is what certificate authorities, browsers and openssl x509 -fingerprint -sha256 display. (DANE users will recognise the equivalents of the TLSA selectors 3 0 1 and 2 0 1.) They are not the SPKI pins of the out-of-band key-pinned privacy profile of RFC 7858 §4.2, which are base64 encoded SHA-256 hashes of the SubjectPublicKeyInfo as in RFC 7469: a pin set published in that format cannot be used as it is. A certificate pin no longer matches once the server certificate is renewed, even with the same key; root pins survive such renewals.

What a pin mismatch leads to is configurable per server:

OnPinMismatch Result Logging
Refuse (default) The connection is refused. Security log.
Record The server is used all the same. Security log and secure metrological log, as evidence.
Accept The server is used all the same. Security log.

Record and Accept exist for planned transitions and for the first weeks of rolling out pins in a large fleet. Both must be reported as a security relevant event.

Trust on first use. Instead of being given a pin, a server can be told to learn one: TrustOnFirstUse = Root or Certificate. The first time its certificate is accepted without any mismatch, the fingerprint of its root CA (or of the certificate itself) is written into the persistent configuration of the server, exactly as if somebody had typed it, and from then on the server is held to it. Nothing is learned from a certificate that was only tolerated by Record or Accept. Learning a pin is a configuration change and therefore logged and, via OCPP, reported (section 3.1.4).

Change detection. Independent of pins, the station remembers per server the certificate and root CA it was last believed with, and since when, across reboots. A server showing another certificate than before is logged as a warning, even if no pin forbids it. This turns the silent replacement of a resolver — or of its certificate — into an auditable event.

Revocation. Revocation should be checked where an OCSP responder or CRL is reachable. A root CA of one's own often has no revocation infrastructure; a status that cannot be obtained should not be held against the certificate, but a certificate that is known to be revoked must be refused. (Reference implementation: so for chains that end at a root CA of the station's own store. Chains to root CAs of the operating system are currently not checked for revocation.)

2.4 Multiple Name Servers

A charging station may be configured with several name servers (the reference implementation allows up to 16). The reference implementation sends every query to all configured servers in parallel and uses the first valid answer; a server answering SERVFAIL is asked again up to MaxRetries times, and every server has its own query timeout. This gives the best latency and resilience, but it has a security consequence:

The security of name resolution is the security of the weakest configured server.

When one encrypted and one clear text server are configured, an on-path attacker simply answers faster on the clear text path. Mixed sets must therefore be avoided. A charging station should warn about a configuration that mixes encrypted and unencrypted transports, and may offer to refuse unencrypted servers altogether (DNSClientController.EncryptedOnly, section 3.1.1). Priority bands as known from the Secure Time Synchronization paper (servers with lower priority values are asked first, servers with equal values in parallel) are an optional extension for deployments that need a fallback resolver.

2.5 Bootstrapping

A name server configured by its domain name is a name that has to be resolved first — by a resolver that is not yet authenticated. RFC 8310 §7 discusses this bootstrap problem. Charging stations should therefore configure their name servers by IP address, and authenticate them by a certificate issued for that address, narrowed by pins where possible. A pin never replaces the name check of section 2.3: without an authentication domain name, a server dialled by its address needs that address in its certificate. An optional authentication domain name (ADN) as defined by RFC 8310 — the name the certificate is checked against when the server is dialled by its address — is described as an optional variable in section 3.1.2.

Networks can also announce encrypted resolvers, via DHCP and IPv6 router advertisements (RFC 9463, DNR) or via the resolver itself (RFC 9462, DDR). Whether a charging station may accept such announcements is a policy decision of the CPO; the safe default is to use only resolvers configured via OCPP or by the manufacturer.

2.6 DNSSEC

Encrypted transports authenticate the resolver, not the data: a compromised or misconfigured resolver can still return wrong answers. DNSSEC authenticates the data itself, from the root zone down.

Reference implementation: The DO bit is configurable and the DNSSEC status of an answer is shown in the diagnostic look-up. Hermod contains a DNSSEC validator, but resolution does not validate inline yet; aggressive NSEC caching (RFC 8198) stays dormant until it does.

2.7 Robustness and Privacy

Reference implementation: All of the above. Queries are padded on TCP, TLS and HTTPS, and connections follow the edns-tcp-keepalive option of RFC 7828.

2.8 Logging

Reference implementation: All of the above. Changes are written as one line listing every changed setting, e.g. DNS configuration changed: servers = tls://192.0.2.53:853, DNSSEC OK = True., and the web interface adds who made the change. Certificate verdicts are tagged dns, certificates and security.

3. Secure DNS OCPP Client Configuration

As with time synchronization, OCPP v1.6+SE and v2.x differ fundamentally in how a charging station is configured: OCPP v1.6 uses a flat key-value store, OCPP v2.x its Device Model. Both are covered. The reference implementation keeps one configuration section (dns, see section 3.4) and maps both OCPP variants onto it, so the web interface, the configuration file and OCPP can never disagree.

OCPP v2.x does not define any component for name resolution, and the NetworkConnectionProfile of SetNetworkProfileRequest has no DNS settings. This paper therefore defines two new logical components. Their names end in …Controller, like those of the Secure Time Synchronization paper, so that both extensions are named alike.

3.1 OCPP v2.x Client Configuration

3.1.1 DNS Client Controller

The component DNSClientController has no instance. It holds what applies to name resolution as a whole.

Variable Name req/opt Mutability Data Type Default Value Values List / Limits Description Reference Implementation
Enabled required rw boolean true - Whether the charging station resolves names at all. While false, no name server is asked and no name is resolved, the name of the CSMS included (section 3.1.3); the configured servers are kept and used again when switched back on. dns.enabled
QueryTimeout optional rw decimal (system) 0.1 … 120 (s) How long one query may take, unless a server has a timeout of its own. Unit: s. dns.queryTimeoutSeconds, 10 s when not set
MaxRetries optional rw integer 1 0 … 255 How often a server that did not answer, or answered SERVFAIL, is asked again. dns.maxRetries
RecursionDesired optional rw OptionList Set Set, Unset, Default Whether the RD bit is set (Set), cleared (Unset), or left to the implementation (Default). dns.recursionDesired (true / false / null)
UseCache optional rw boolean true - Whether answers are cached for their time to live. dns.useCache
DNSSECOK optional rw boolean false - Whether the DNSSEC OK (DO) bit is set, i.e. whether signatures are requested. dns.dnssecOK
FollowCNAMEs optional rw boolean true - Whether CNAME and DNAME chains are followed. dns.followCNAMEs
MaxCNAMEFollows optional rw integer 8 0 … 255 The maximal length of a followed alias chain. dns.maxCNAMEFollows
MaxServers optional ro integer 16 - The number of DNSServerController instances this charging station offers. constant, 16
UDPPayloadSize optional ro integer - - The EDNS(0) UDP payload size advertised in queries. fixed at start
ClientSubnet optional ro string "" - The EDNS Client Subnet sent with every query, e.g. "203.0.113.0/24"; empty when none is sent. fixed at start
EncryptedOnly optional rw boolean false - When true, configuring a server with an unencrypted transport (UDP, TCP) is refused, and servers already configured with one are no longer asked. See section 2.4. not implemented
ServerSource optional rw OptionList System System, Manual System: the name servers of the operating system or the network configuration (e.g. DHCP), comparable to ClockCtrlr.NtpSource. Manual: the servers of the DNSServerController instances. read-only: Manual once servers are configured

Changing Enabled, QueryTimeout or any other setting takes effect immediately, without a reboot, for every service of the charging station that resolves names.

See also: C# Reference Implementation

3.1.2 DNS Server Controller

The component DNSServerController exists in the fixed instances "1" … "<MaxServers>". Each instance is a slot for one name server. A slot whose Address is empty is unused. The Device Model has no way to create component instances via SetVariablesRequest; fixed slots make adding a server an ordinary SetVariables of its Address — comparable to the configuration slots of SetNetworkProfileRequest.

All servers of all used slots are asked in parallel (section 2.4); the slot number is an identifier, not a priority. A charging station may compact the used slots after a request, i.e. servers behind an emptied slot move up. Within one request, slot numbers keep referring to the servers they referred to at its start. A CSMS should therefore send the complete intended list of servers in one SetVariablesRequest and read it back afterwards.

Variable Name req/opt Mutability Data Type Default Value Values List / Limits Description Reference Implementation
Address required rw string "" ≤ 253 characters The IP address (IPv4 or IPv6) or the domain name of the name server. Empty: the slot is unused. IP addresses are recommended (section 2.5). dns.servers[n].address
Port optional rw integer (by transport) 1 … 65535 The port of the name server. When not set: 53 for UDP/TCP, 853 for TLS, 443 for HTTPS*. dns.servers[n].port
Transport optional rw OptionList UDP UDP, TCP, TLS, HTTPS, HTTPS_GET The transport, see section 2.1. The valuesList shall list only what the charging station supports. dns.servers[n].transport
QueryTimeout optional rw decimal (DNSClientController.QueryTimeout) 0.1 … 120 (s) How long a query to this server may take. Unit: s. dns.servers[n].queryTimeoutSeconds
CertificatePins optional rw string "" comma separated, ≤ 16 SHA-256 fingerprints (64 hexadecimal digits, with or without colons) of the certificates this server may show. Only allowed for TLS and HTTPS*. certificateFingerprint(s)
RootPins optional rw string "" comma separated, ≤ 16 SHA-256 fingerprints of the root CA certificates this server's chain may end at. Only allowed for TLS and HTTPS*. rootFingerprint(s)
OnPinMismatch optional rw OptionList Refuse Refuse, Record, Accept What a pin mismatch leads to, see section 2.3. Only allowed when the server is held to a pin or learns one. onMismatch
TrustOnFirstUse optional rw OptionList None None, Root, Certificate Whether the server learns a root pin or a certificate pin from the first certificate it is believed with. When a pin of that kind is set already, nothing is learned. Only allowed for TLS and HTTPS*. trustOnFirstUse
AuthenticationName optional rw string "" ≤ 253 characters The authentication domain name of RFC 8310: the name the certificate is checked against and sent as SNI, when the server is dialled by its IP address. not implemented
RootCAs optional rw string "" ≤ 50 characters The certificateGroup of NameServerRootCertificate root CAs this server's chain must end at (section 3.1.3). Compatible with NTPClientController.RootCAs of the Secure Time Synchronization paper. not implemented: root pins instead
Enabled optional rw boolean true - Whether this server is asked. A disabled server keeps its configuration. not implemented
Priority optional rw integer 0 0 … 255 Servers with lower values are asked first, servers with the same value in parallel (section 2.4). not implemented
Problem optional ro boolean false - true while the last TLS handshake with this server was refused. Standardized variable name of OCPP; can be monitored. last verdict
CertificateStatus optional ro OptionList "" Accepted, Recorded, Tolerated, PinMismatch, Untrusted, WrongName, NoCertificate The verdict of the last TLS handshake. Empty before the first one and for unencrypted transports. last verdict
CertificateFingerprint optional ro string "" - The SHA-256 fingerprint of the certificate the server showed at its last handshake. last verdict
RootFingerprint optional ro string "" - The SHA-256 fingerprint of the root CA the chain ended at. last verdict
KnownSince optional ro dateTime - - Since when the server is believed with its current certificate (change detection, section 2.3). known servers

The value of CertificatePins and RootPins is a comma separated list of fingerprints and not a MemberList, because a MemberList only takes values of the valuesList. Writing a list is limited by SetVariableData.attributeValue, 1000 characters in OCPP 2.0.1 and 2500 in OCPP 2.1, or less (see DeviceDataCtrlr.ConfigurationValueSize). In OCPP 2.0.1 at most 15 fingerprints without colons fit; in OCPP 2.1 all 16 fit, with colons as well. Reading is limited by ReportingValueSize: 16 fingerprints without colons take 1039 characters.

When trust on first use learns a pin, the value of CertificatePins or RootPins changes without any request of the CSMS. A CSMS that wants to know can set a Delta monitor on these variables.

See also: C# Reference Implementation

3.1.3 OCPP v2.x Command Extensions

SetVariablesRequest

Several variables of one name server depend on each other: a pin is only allowed for an encrypted transport, the default port depends on the transport, and OnPinMismatch only makes sense with a pin. Applied one by one, a change from UDP to TLS with a root pin succeeds or fails depending on the order of the SetVariableData entries. Therefore:

InstallCertificateRequest

The InstallCertificateUseEnumType is extended by "NameServerRootCertificate", analogous to the "NetworkTimeRootCertificate" of the Secure Time Synchronization paper, and uses the same optional certificateGroup property. A root CA of this type vouches for name servers only, not for the CSMS, not for NTS-KE servers. GetInstalledCertificateIdsRequest and DeleteCertificateRequest accept the new type as well. Deleting a root CA that the chain of a configured name server ends at is subject to the same check as a change of the configuration (section 3.1.3, "A CSMS must not cut itself off"), and is answered Failed when the check fails.

{
    "$schema": "http://json-schema.org/draft-06/schema#",
    "$id": "urn:OCPP:Cp:2:2025:1:InstallCertificateRequest",
    "comment": "OCPP 2.1 Edition 1 (c) OCA, Creative Commons Attribution-NoDerivatives 4.0 International Public License",
    "definitions": {
        "InstallCertificateUseEnumType": {
            "description": "Indicates the certificate type that is sent.",
            "javaType": "InstallCertificateUseEnum",
            "type": "string",
            "additionalProperties": false,
            "enum": [
                "V2GRootCertificate",
                "MORootCertificate",
                "ManufacturerRootCertificate",
                "CSMSRootCertificate",
                "OEMRootCertificate",
                "NetworkTimeRootCertificate",
                "NameServerRootCertificate"
            ]
        },
        ...
    },
    "type": "object",
    "additionalProperties": false,
    "properties": {
        "certificateType": {
            "$ref": "#/definitions/InstallCertificateUseEnumType"
        },
        "certificateGroup": {
          "description": "A X.509 certificate group.",
          "type": "string",
          "maxLength": 50
        },
        "certificate": {
            "description": "A PEM encoded X.509 certificate.",
            "type": "string",
            "maxLength": 10000
        },
        "customData": {
            "$ref": "#/definitions/CustomDataType"
        }
    },
    "required": [
        "certificateType",
        "certificate"
    ]
}

Reference implementation: Root CAs for name servers are TLS roots of the node's certificate store with the usage dns. Instead of root CA groups per server, the reference implementation holds servers to root pins; a pinned root CA that is in the store is used as a trust anchor for that server even when it was not installed for name servers.

3.1.4 Security Events

The following SecurityEventNotificationRequest types are used. ReconfigurationOfSecurityParameters is a security event of OCPP 2.x; the others are proposed by this paper. The techInfo names the server, e.g. tls://192.0.2.53:853, and the fingerprints involved.

Type When
ReconfigurationOfSecurityParameters The DNS configuration was changed by anybody but the CSMS itself, e.g. locally or via a web interface — or a pin was learned by trust on first use.
InvalidNameServerCertificate A TLS handshake with a name server was refused: wrong name, untrusted chain, no certificate, or a pin mismatch with OnPinMismatch = Refuse. Sent once per change of the verdict, not at every attempt.
NameServerPinMismatchTolerated A server was used despite a pin mismatch (Record or Accept).
NameServerCertificateChanged A server was believed with another certificate or root CA than before.

3.2 OCPP v1.6+SE Client Configuration

The following configuration keys map the same configuration onto OCPP v1.6+SE. Comma separated lists (CSL) follow the rules of the Secure Time Synchronization paper, with one exception: an empty or missing entry of dns.ports means the default port of that server's transport, because a port repeated from a previous server would be the wrong port as soon as the transports differ.

Pin lists cannot be written as entries of a comma separated list of servers, so they have one key per server, numbered from 1 in the order of dns.servers. OCPP v1.6 limits a configuration value to 500 characters, so at most 7 fingerprints fit into one key.

Key Name req/opt Accessibility Type Default Value Example Description
dns.enabled required rw Boolean true - See DNSClientController.Enabled.
dns.servers optional rw CSL String "" "192.0.2.53, 198.51.100.53" The name servers, see DNSServerController.Address.
dns.ports optional rw CSL String "" "853, 853" See DNSServerController.Port.
dns.transports optional rw CSL String "UDP" "TLS, TLS" See DNSServerController.Transport.
dns.queryTimeouts optional rw CSL String "" "2, 3" Per server, in seconds; empty: dns.queryTimeout.
dns.queryTimeout optional rw Decimal (system) 3 See DNSClientController.QueryTimeout.
dns.maxRetries optional rw Integer 1 - See DNSClientController.MaxRetries.
dns.recursionDesired optional rw String "Set" "Default" See DNSClientController.RecursionDesired.
dns.useCache optional rw Boolean true - See DNSClientController.UseCache.
dns.dnssecOK optional rw Boolean false - See DNSClientController.DNSSECOK.
dns.followCNAMEs optional rw Boolean true - See DNSClientController.FollowCNAMEs.
dns.maxCNAMEFollows optional rw Integer 8 - See DNSClientController.MaxCNAMEFollows.
dns.encryptedOnly optional rw Boolean false - See DNSClientController.EncryptedOnly.
dns.onPinMismatch optional rw CSL String "Refuse" "Refuse, Record" See DNSServerController.OnPinMismatch.
dns.trustOnFirstUse optional rw CSL String "None" "Root, None" See DNSServerController.TrustOnFirstUse.
dns.certificatePins.n optional rw CSL String "" "41C7…3F61" The certificate pins of the n-th server.
dns.rootPins.n optional rw CSL String "" "9D2E…D8E" The root pins of the n-th server.

A ChangeConfiguration.req changes one key at a time, so the order-dependency described in section 3.1.3 cannot be avoided by a transaction. A charging station SHALL therefore validate each key against the configuration as it would be after the change, and SHALL answer Rejected when the result would be inconsistent (e.g. a pin for a server that is still asked over UDP). A CSMS has to change the transports before it sets pins, and remove pins before it switches a server back to an unencrypted transport. The rules of section 3.1.3 for emptying the list of servers, for switching name resolution off and for the host names of the CSMS apply as well; in OCPP v1.6 Rejected carries no reason.

InstallCertificate.req of the OCPP v1.6 Security Extensions is extended by "NameServerRootCertificate" and certificateGroup in the same way as shown for the Secure Time Synchronization paper.

3.3 Example

Two CPO-operated resolvers reached over DNS-over-TLS, both issued certificates for their IP addresses by the CPO's own root CA, which was installed as NameServerRootCertificate. The first is pinned to that root CA, the second learns its root on first use; signatures are requested.

OCPP v2.x SetVariablesRequest:

{
  "setVariableData": [
    { "component": { "name": "DNSServerController", "instance": "1" }, "variable": { "name": "Address"         }, "attributeValue": "192.0.2.53" },
    { "component": { "name": "DNSServerController", "instance": "1" }, "variable": { "name": "Transport"       }, "attributeValue": "TLS" },
    { "component": { "name": "DNSServerController", "instance": "1" }, "variable": { "name": "RootPins"        }, "attributeValue": "9D2E4F6A8B0C1D3E5F7A9B1C3D5E7F9A0B2C4D6E8F0A1B3C5D7E9F1A2B4C6D8E" },
    { "component": { "name": "DNSServerController", "instance": "2" }, "variable": { "name": "Address"         }, "attributeValue": "198.51.100.53" },
    { "component": { "name": "DNSServerController", "instance": "2" }, "variable": { "name": "Transport"       }, "attributeValue": "TLS" },
    { "component": { "name": "DNSServerController", "instance": "2" }, "variable": { "name": "TrustOnFirstUse" }, "attributeValue": "Root" },
    { "component": { "name": "DNSServerController", "instance": "3" }, "variable": { "name": "Address"         }, "attributeValue": "" },
    { "component": { "name": "DNSClientController" },                  "variable": { "name": "DNSSECOK"        }, "attributeValue": "true" },
    { "component": { "name": "DNSClientController" },                  "variable": { "name": "QueryTimeout"    }, "attributeValue": "3" }
  ]
}

OCPP v1.6+SE:

dns.servers     = "192.0.2.53, 198.51.100.53"
dns.transports  = "TLS"
dns.rootPins.1  = "9D2E4F6A8B0C1D3E5F7A9B1C3D5E7F9A0B2C4D6E8F0A1B3C5D7E9F1A2B4C6D8E"
dns.trustOnFirstUse = "None, Root"
dns.dnssecOK    = true
dns.queryTimeout = 3

3.4 Reference Implementation Configuration

The section of the configuration file the reference implementation keeps — and which its web interface and its HTTP API read and write in exactly this shape — for the example above:

"dns": {
  "enabled": true,
  "servers": [
    { "address": "192.0.2.53",    "transport": "TLS",
      "rootFingerprint": "9D2E4F6A8B0C1D3E5F7A9B1C3D5E7F9A0B2C4D6E8F0A1B3C5D7E9F1A2B4C6D8E" },
    { "address": "198.51.100.53", "transport": "TLS", "trustOnFirstUse": "root" }
  ],
  "queryTimeoutSeconds": 3,
  "dnssecOK": true
}

Every key is optional; what the section does not mention is left as the charging station was built with, and a station built with nothing uses the name servers of its operating system. A server may also be written as a plain string ("192.0.2.53"), meaning UDP on port 53. Several pins of a kind are written as a list ("rootFingerprints": [ … ]). After the first handshake with the second server, the station has added the learned "rootFingerprint" to its entry.

3.5 Example Configuration Using systemd-resolved or Unbound

For Linux based charging stations that use the resolver of the operating system, the following configurations implement the strict profile. Neither supports pinning. Unbound validates against the CA bundle given as tls-cert-bundle, which should contain only the root CAs of the configured resolvers; systemd-resolved validates against the CA bundle of the operating system, which cannot be narrowed per resolver.

# /etc/systemd/resolved.conf
[Resolve]
DNS=192.0.2.53#resolver1.cpo.example 198.51.100.53#resolver2.cpo.example
DNSOverTLS=yes
# No compiled-in public fallback resolvers
FallbackDNS=
Domains=~.
# /etc/unbound/unbound.conf
server:
    tls-cert-bundle: /etc/unbound/cpo-resolver-roots.pem
    auto-trust-anchor-file: /var/lib/unbound/root.key

forward-zone:
    name: "."
    forward-tls-upstream: yes
    forward-addr: 192.0.2.53@853#resolver1.cpo.example
    forward-addr: 198.51.100.53@853#resolver2.cpo.example

The name after # is the authentication domain name of RFC 8310 (DNSServerController.AuthenticationName). Unbound additionally validates DNSSEC locally, with an RFC 5011 managed trust anchor.

4. Operational Guide

CPOs must configure not only their charging stations, but also the networks they are connected to: private APNs, VPNs, site networks and firewalls.

4.1 Firewall Rules

4.2 CPO-Operated Resolvers

For larger fleets, CPOs should operate their own recursive resolvers, reachable from their private APNs or VPNs, and issue their certificates from a CPO root CA dedicated to that purpose:

4.3 Public Resolvers

Public DoT/DoH resolvers are acceptable where no CPO resolver is reachable. They should be pinned by their root CA (not by their leaf certificate, which changes frequently), and the CPO should monitor NameServerCertificateChanged events to learn about changes before pins become a problem.

4.4 Failure Behaviour

When no name server can be reached or authenticated, a charging station cannot reach its CSMS by name. Charging must continue as defined for an offline CSMS connection. The charging station should keep trying, log the start and the end of the outage, and report it once the CSMS is reachable again. Section 3.1.3 keeps a CSMS from causing such an outage by a change of the configuration.

5. Test Criteria

# Test Expected result
T1 ACID: Transport = UDP and RootPins on the same server in one SetVariablesRequest. The causing entry Rejected, all other DNS entries Rolledback; configuration unchanged.
T2 IndependentRequests: on an existing UDP server, RootPins before Transport = TLS; then the opposite order. First order: RootPins Rejected, Transport Accepted. Opposite order: both Accepted. With ACID: both orders Accepted.
T2a IndependentRequests: RootPins, Transport = TLS and Address for an unused slot, in this order. All Accepted; the log shows one change, and no clear text server was ever configured.
T3 DoT server presents a certificate for another name or address. Refused, even when it matches a pin; InvalidNameServerCertificate; Problem = true, CertificateStatus = WrongName.
T4 DoT server's chain ends at a root installed only as NetworkTimeRootCertificate or CSMSRootCertificate. Refused (Untrusted).
T5 Same server, root installed as NameServerRootCertificate. Accepted.
T6 Pin mismatch with OnPinMismatch = Refuse / Record / Accept. Refused / used and logged in security and metrological log / used and logged in security log.
T7 TrustOnFirstUse = Root, first handshake. RootPins contains the root's fingerprint, also after a reboot; security log entry; ReconfigurationOfSecurityParameters.
T8 TrustOnFirstUse = Root, server already holds a root pin. Nothing learned.
T9 The server certificate is replaced by another one that is equally valid. Accepted; NameServerCertificateChanged; KnownSince updated.
T10 The same refused server, 100 connection attempts. One security log entry and one security event, not 100.
T11 Pins of a server are changed while a DoT connection to it is open. The connection is closed; the next query makes a new handshake judged by the new pins.
T12 One encrypted and one clear text server; attacker answers on UDP first. Documented weakness (section 2.4); with EncryptedOnly = true the clear text server is refused.
T13 Block TCP port 853. No fallback to UDP port 53.
T14 Empty every Address, once with Enabled = true and once with Enabled = false. Rejected both times; the servers are kept.
T15 More than MaxServers servers, more than 16 pins, timeouts out of range. Rejected with ValueOutOfRange.
T16 Configuration change via the local web interface. Security log names who changed what; ReconfigurationOfSecurityParameters to the CSMS.
T17 Persistence fails (e.g. read-only file system). InternalError; nothing changed in effect.
T18 GetBaseReport(FullInventory). DNSClientController and all MaxServers instances of DNSServerController, with characteristics and value lists.
T19 Enabled = false while the CSMS is dialled by its domain name. Rejected.
T20 Via OCPP, replace the name servers by one whose certificate is untrusted, while the CSMS is dialled by its domain name. Then the same with a server that works. First: all entries Rejected with reasonCode CSMSUnreachable, configuration unchanged. Then: Accepted.
T21 DeleteCertificate of the NameServerRootCertificate that every configured server's chain ends at, while the CSMS is dialled by its domain name. Failed; the root CA is kept.

6. Relation to Other White Papers

ToDo's