DER & inverter identity
Bind the IEEE 2030.5 LFDI a DER already carries to a routable IPv6 /128 derived from the device's own public key, so the address is the inverter: forge-proof, tenant-private, DNSSEC-anchored, DANE-pinned, and revocable worldwide in one call. It's the off-switch its own PKI never had.
This is the spine of the energy vertical, and it is shipped and live. Everything else (the grid-API-abuse cure, the platform integrations, the NERC-CIP evidence) builds on one idea: a DER's network address stops being a disposable label a proxy can rotate and becomes a cryptographic fact only that device's silicon can stand behind. IEEE 2030.5 already computes a genuinely good key-derived name for every inverter, the LFDI, and then locks it in a private root that can never revoke it. Whisper keeps that property and adds the two things it lacks.
Two tiers, per Postel's Law. With no API key anyone can verify a DER's identity from stock tools (dig, curl, RDAP), because the identity is public by design. With your key you provision and govern: mint the /128, source-bind its egress, pull its logs, watch who's enumerating it, and revoke it. Verification never needs an account; the control plane does.
The LFDI: a key-derived name, in a cage
Start with what the grid already has, because it's better than most people realize. Under CA Rule 21 and the IEEE 2030.5 CSIP profile, every EndDevice is named by its LFDI, the Long Form Device Identifier. The LFDI is not a serial number a factory typed into a spreadsheet. It is the leftmost 160 bits (the first 20 octets) of the SHA-256 hash of the device's own DER-encoded X.509 certificate, written as 40 hex digits grouped in fours. Its short form, the SFDI, is the leftmost 36 bits of the same hash plus a single decimal check digit. In other words, the standard already hashes the device's own key material into a globally-unique, structured name: the same instinct Whisper is built on. That's a real head start.
The trouble isn't the name. It's the four walls around it. The LFDI's trust hangs off a private hierarchy (SERCA → MCA → MICA, the SunSpec/Kyrio managed PKI) where devices carry SERCA trust anchors and each path chains to exactly one root. That's deliberately not Web PKI, so nothing outside the utility's own ecosystem can validate it. Aggregators register LFDIs out-of-band, publishing an LFDI-plus-site-ID pairing to the utility server by hand. And the certificates are, by design, permanent:
Per the CSIP managed-PKI model: "no certificates within the MPKI can be revoked because they are embedded permanently within devices; CAs are not required to issue CRLs nor provide OCSP". In its own words, "life-long certificates that cannot be updated or revoked and must be known privately."
So the LFDI is a good key-derived name that is nonetheless boxed in on four sides at once:
| The LFDI already has | The LFDI still lacks |
|---|---|
Key-derived identity: 160 bits of SHA-256 over the device's own certificate; the EndDevice primary key |
Not addressable: an application-layer string, never a routable network endpoint you can reach or authorize against |
| Globally unique & structured: flows through every CSIP / Rule 21 deployment | Not publicly verifiable: trust lives in the private SERCA→MCA→MICA root, not Web PKI; useless off-ecosystem |
| Mandated: the default identifier under CA Rule 21 and IEEE 2030.5 | Allow-listed by hand: LFDI + site ID registered out-of-band, per utility, per aggregator |
| Bound to a cert only the device holds | Non-revocable: life-long, with no CRL, no OCSP, and no off-switch at all |
Read the right-hand column as a to-do list. Whisper does exactly those four things, without touching the left-hand column and without re-keying the 25M+ inverters already in the field.
The cure: a routable, revocable /128
Whisper keeps the LFDI's one good property (identity derived from the device's own key) and adds the two the private root withholds: public verifiability and DNS-TTL, cross-operator revocation. It does this by giving the device a real, routable IPv6 /128 out of 2a04:2a01::/32 (announced by AS219419) that is a deterministic function of the device's public key with the LFDI as the domain separator, then anchoring that address into DNS so anyone can prove it and one call can retire it.
/128 and gives it the off-switch its own PKI explicitly lacks.Because the address is derived from a key only that device holds, you cannot present a DER identity whose key you don't have. "One token → a whole fleet" becomes physically impossible; a stolen bearer off the wrong address is inert; and every forgery is a DNSSEC/DANE inconsistency any verifier catches for free. That is the whole point of moving trust from a claim the caller carries to the machine on the other end.
How the derivation works
The /128 isn't drawn from a pool and written into a database. It is computed, the same way on every node, from inputs the device already has. Three things go in:
| Input | What it is | Where it lives |
|---|---|---|
| Device public key | the SubjectPublicKeyInfo (SPKI) of the device's key: the public half of its IEEE 2030.5 EndDevice certificate, a SunSpec/Kyrio device cert, a TPM, or a secure element |
the public half is submitted; the private key never leaves the device |
| LFDI | the IEEE 2030.5 Long Form Device Identifier the unit already carries, used here as the domain separator (a bare DER serial or SFDI is accepted too) | submitted with the request; the public index |
| ECU / component serial (optional) | a per-component domain separator, so one site can hold many addressable identities (the inverter, a battery gateway, a specific controller) | optional; omit it for a single per-device address |
Those inputs are combined by a one-way derivation, with a Whisper-held secret mixed in, into a stable, unguessable interface identifier scoped to your fleet:
# inputs -> a stable, forge-proof interface identifier
derive( device public key, LFDI [, component serial], your fleet ) --> 64 uniform bits
# the /64 prefix is your tenant block; the low 64 bits are the derived id
/128 = < your tenant /64 prefix > : < derived interface id >
Four properties fall straight out of that derivation, and each one is load-bearing:
- Deterministic. The same
(key, LFDI[, serial])yields a byte-identical/128every time, on every server: exactly one candidate, never a random retry. A reconnecting inverter re-derives its own address; both of our authoritative nodes mint the identical identity with zero replication between them. - Forge-proof. The address is a function of a key only the device holds. An attacker with the LFDI and even the device's public key still cannot become that inverter: the server-side secret and the DANE pin (below) are the parts they can never produce.
- Tenant-bound & fleet-unlinkable. Your tenant's own
/64is folded into the derivation. The same key + LFDI under a different aggregator produces a different address, so an outsider cannot derive or enumerate a device's address in a fleet they don't control, and a unit is not linkable across operators by address suffix. The LFDI flows through every CSIP deployment and is not a secret, yet the LFDI alone yields nothing: you cannot go LFDI →/128without the key, there is no enumerable directory, and RDAP / reverse-DNS return the registry object, never the device's whereabouts. - Liberal in, strict out. The LFDI is accepted generously (whitespace stripped, case-folded, the display grouping removed), then held to exactly 40 hex characters; a bare DER serial is accepted where a unit has no LFDI. A malformed identifier fails closed with a clear message, never a silent wrong address.
The moment the address is derived it is published as a full identity, atomically: an AAAA, a forward-confirmed PTR, and a DANE-EE TLSA 3 1 1 record that pins the device's leaf key directly, all DNSSEC-signed to the IANA root and registered in RDAP. That TLSA pin is what turns "the address is derived from a key" into "the address is provable against that key by anyone." See DANE & TLSA for the byte-for-byte record and DNSSEC for the chain it hangs from.
The private key never moves. The device submits only its public SPKI, the same public half of the EndDevice / SunSpec-Kyrio / TPM / secure-element key it already holds. The server derives a public address from public inputs plus a server-side secret; it never sees, holds, or derives the device's private key. The inverter proves ownership later by presenting its own key against the DANE pin.
You can pin the cert you already speak. If your CSIP head-end already terminates the device's IEEE 2030.5 EndDevice certificate, you can publish a DANE TLSA record over DNSSEC that pins that endpoint certificate. That turns the private single-root trust into something any relying party can validate against the IANA root, and cuts single-CA trust risk, with no change to the device. Whisper's derived /128 and a DANE-pin of your existing 2030.5 cert are complementary: one gives the device a publicly verifiable address, the other makes its existing certificate publicly verifiable.
Provision a DER identity
Provisioning is one control-plane call: whisper.agents with op:'connect', tier:'wireguard', the device's public SPKI, and the LFDI passed as device_id. It returns the deterministic /128 and a ready WireGuard configuration so the DER's traffic sources from its own identity. The endpoint is POST https://graph.whisper.security/api/query, authed with an X-API-Key header. No key ever travels in the body.
CALL whisper.agents({op:'connect', args:{
tier: 'wireguard',
identity_public_key: '<base64 SubjectPublicKeyInfo of the device key>',
device_id: '3F2504E04F8911D39A0C0305E82C33018B2E44F9' // the IEEE 2030.5 LFDI
// ecu_serial: 'INV-GW-07' // optional: a distinct /128 per component
}}) YIELD op, ok, status, result, error
RETURN op, ok, status, result, error
With stock tools: just curl, no Whisper software. A quoted heredoc keeps the Cypher single-quotes intact so it pastes and runs as-is:
curl -s https://graph.whisper.security/api/query \
-H "X-API-Key: whisper_live_xxx" \
-H "content-type: application/json" \
-d @- <<'JSON' | jq .
{"query":"CALL whisper.agents({op:'connect', args:{tier:'wireguard', identity_public_key:'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...<SPKI>...', device_id:'3F2504E04F8911D39A0C0305E82C33018B2E44F9'}}) YIELD op, ok, status, result, error RETURN op, ok, status, result, error"}
JSON
The response is the standard envelope; result carries the derived address and the transport. Because the device holds its own key, no private key is ever returned: only the public identity and the config that binds egress to it:
{
"op": "connect", "ok": true, "status": 200,
"result": {
"tier": "wireguard",
"address": "2a04:2a01:5e0::50c", // the deterministic /128
"fqdn": "lfdi-3f2504e0.der.<tenant>.agents.whisper.online",
"server_public_key": "…",
"endpoint": "…:51820",
"dns": "2a04:2a01:0:53::53",
"wireguard_config": "[Interface]\nAddress = 2a04:2a01:5e0::50c/128\n…"
},
"error": null
}
Drop the returned wireguard_config onto the DER's communication card or telematics unit (or feed it to wireproxy for a no-root, userspace tunnel) and every packet it sends now sources from its own /128. The DERMS head-end authorizes on that address (a forge-proof, attributable, revocable network identity) instead of a token anyone could carry. For the full transport mechanics and the SOCKS5 / AnyIP alternatives, see Connect & egress; for every other op on this same endpoint, the Control plane reference.
The whisper CLI ships create --register, verify --trustless, policy, logs, and kill --revoke. A dedicated --lfdi flag is on the roadmap, not shipped. Provision DERs today via the control-plane call above, which is live. When the flag lands it will be a thin wrapper over exactly this call. The device_id argument is generic on purpose: pass an LFDI, an SFDI, or a bare DER serial, whatever native identifier the unit carries.
Idempotent, with honest errors
Because the address is derived, provisioning is naturally idempotent, and the failure modes are clear rather than surprising. Postel all the way down:
| You send | You get |
|---|---|
| the same key + LFDI again (same tenant) | the same /128: a re-derivation, not a new allocation |
| the same key with a different LFDI (same tenant) | 409: the reused identity is never silently re-pinned to a mismatched address |
a non-string device_id (or ecu_serial) |
400 with a helpful detail, never an opaque 500 |
device_id without identity_public_key |
400: a device derives its address from its own key |
Verify: keyless, no account
The identity half is public on purpose: anyone (a utility allow-listing a sanctioned DER, an ISO reconciling a dispatch, an auditor, a suspicious peer) can prove a device's /128 without a Whisper account and without trusting Whisper's word. Four independent checks, all from tools already on the machine:
# 1. Forward-confirmed reverse DNS: the address names the DER, the name resolves back
dig -x 2a04:2a01:5e0::50c +short
lfdi-3f2504e0.der.<tenant>.agents.whisper.online.
# 2. The keyless verdict endpoint (takes an address or an FQDN; ?ip=<target> also accepted)
curl -s https://whisper.online/verify-identity/2a04:2a01:5e0::50c | jq .
{
"is_whisper_agent": true,
"dane_ok": true,
"jws_ok": true,
"evidence": { "aaaa": "...", "ptr": "...", "tlsa": "3 1 1 b653a4ef…fcb82d1d" }
}
# 3. The registry record: RDAP, IP-anchored to the /128
curl -s https://whisper.online/ip/2a04:2a01:5e0::50c | jq '.handle, .parentHandle'
# 4. The full chain re-derived on YOUR machine, against the IANA root: Whisper NOT in the trust path
whisper verify --trustless lfdi-3f2504e0.der.<tenant>.agents.whisper.online
A target that isn't a Whisper identity gets a clean 200 {"is_whisper_agent": false}. A negative verdict is a successful answer, not an error; only genuinely malformed input draws a 400, never a 500. --trustless is the strong form: it validates DNSSEC from the root in-process, on your resolver, so the proof holds even for a party that won't take Whisper's word for anything. The full keyless walk lives in Verify an agent.
Revoke: worldwide, in one call
A compromised or decommissioned inverter is one revoke away from having no network identity anywhere. The call tears down the /128, its PTR, and its DANE pin across both authoritative servers, and the change propagates at DNS-TTL speed:
CALL whisper.agents({op:'revoke', args:{agent:'2a04:2a01:5e0::50c'}})
# prove it: zero Whisper software, the same stock tools that proved it existed:
dig -x 2a04:2a01:5e0::50c +short # -> nothing
curl -s https://whisper.online/verify-identity/2a04:2a01:5e0::50c
# -> {"is_whisper_agent": false, ...}
Revocation isn't a database flag you have to trust; it's provable the same way the identity was: the reverse lookup goes empty and the keyless verdict flips to false for everyone, everywhere, at once. This is precisely what the LFDI's own MPKI forbids: life-long certificates that cannot be updated or revoked. Contrast a shared bearer token, where a rotation reaches only the callers you can still reach. Compromise one inverter and you've compromised that inverter, not the fleet. The fleet-takeover failure mode is structurally removed.
The lifecycle, end to end
A DER identity is not a one-shot registration; it tracks the device through its whole service life. Because every /128 is derived, each stage is a plain control-plane call, and each mint or revoke is written to a public, tamper-evident log. Nothing is issued in the dark.
whisper.agents call. A module swap or repower re-keys to a new /128 and revokes the old; every mint and revoke is written to the public log.| Stage | What happens | Call |
|---|---|---|
| Factory key | The device is born with its key; its LFDI is the SHA-256 of the resulting certificate. Nothing is minted yet. | native (no Whisper call) |
| In-life dispatch | At commissioning, derive the /128 and source-bind egress; the DERMS head-end now authorizes the address, not a bearer. |
op:'connect' |
| Module swap / repower | A replaced comms card or a repowered unit carries a new key, so it re-keys to a fresh /128; the old address is revoked in the same breath. |
op:'connect' + op:'revoke' |
| Incident revoke | A compromised unit (or a whole compromised model) is cut off worldwide at DNS-TTL; verify flips to false everywhere. |
op:'revoke' |
| Decommission / resale | A change of aggregator or an end-of-life retire is one revoke and a re-register to the new owner; op:'erase' renders the log leaf's meaning unrecoverable while its proofs stay valid. |
op:'revoke' (+ op:'erase') |
Nothing issued in the dark. Every mint and every revoke along that timeline lands in a public, append-only Merkle transparency log (RFC 6962 tlog-tiles with signed-note checkpoints), Ed25519-signed and anchored to Bitcoin via OpenTimestamps: an auditable, non-repudiable issuance-and-revocation trail your PSIRT and your regulator can replay. Honest status: the log is tamper-evident, signed, and Bitcoin-anchored today, but it is not yet independently witnessed. Our two authoritative nodes co-signing is availability, not independence. The log already speaks the C2SP tlog-witness protocol, so any external witness can co-sign; that step is on the roadmap, and we label it as such rather than overclaim.
Govern a live DER: egress, budget, lookups
Revocation is the kill-switch. In between, the same control plane governs exactly what a live DER may reach, caps it, and tells you who is looking at it. Because egress is source-bound to the device's /128, policy is enforced by name and by address, default-deny:
# default-deny: this inverter may reach ONLY its DERMS head-end and OTA endpoint
whisper policy set --default deny --allow derms.example-vpp.com,ota.example-vpp.com
# per-device firewall (allow/deny by host, cidr, or port) + a daily budget with a kill-switch
CALL whisper.agents({op:'firewall', args:{agent:'2a04:2a01:5e0::50c',
deny:['0.0.0.0/0'], allow:['derms.example-vpp.com:443','ota.example-vpp.com:443']}})
CALL whisper.agents({op:'budget', args:{agent:'2a04:2a01:5e0::50c', max_mb_per_day:50}})
See who's enumerating your fleet, before the command lands. An identity you can prove is also an identity you can watch. Because every DER's name resolves through Whisper's own authoritative DNS and RDAP, the owner can ask who looked: a reconnaissance tripwire the LFDI's private, out-of-band registry never gave you. op:'lookups' returns who resolved or RDAP-queried a device's identity, so you catch an attacker enumerating the fleet in recon, not in the post-mortem:
# who has been resolving / RDAP-querying this DER's identity, and when
CALL whisper.agents({op:'lookups', args:{agent:'2a04:2a01:5e0::50c', window:'24h'}})
# the same reverse-observability view, keyless, per address
curl -s https://whisper.online/ip/2a04:2a01:5e0::50c/lookups | jq .
# -> who resolved this DER's PTR/AAAA/TLSA and hit its RDAP object
Paired with op:'logs' (the device's own outbound activity) you have both halves of the picture: what a DER reaches out to, and who is reaching in to look at it. And because each dispatch and telemetry stream can be signed under the DER's forge-proof /128, the ISO, the utility, and your own market settlement can trust the numbers came from the real device: non-repudiable telemetry, not a spoofed feed. The full policy surface is in Egress governance.
Attribution: name whoever already scraped you
Identity stops the next forgery. To name whoever already scraped a fleet, across rotating clouds and residential proxies, the same API key opens the read-only attribution graph on the same endpoint. whisper.identify takes an address and returns the operator behind it, stitched across the Amazon → Google → Azure hops that a raw last-IP loses:
curl -s https://graph.whisper.security/api/query \
-H "X-API-Key: whisper_live_xxx" \
-H "content-type: application/json" \
-d '{"query":"CALL whisper.identify(\"34.90.x.x\")"}' | jq .
# operator fingerprinted across AWS / GCP / Azure; residential swarm collapsed by JA4
The read-only Cypher surface (identify, origins, walk, variants, history) runs over the same POST https://graph.whisper.security/api/query with your key, and each verb returns a reproducible, replayable JSON evidence chain your OT SOC, your PSIRT, and a regulator can replay. There is no whisper identify CLI subcommand: this is the API call, and it is live. Full verbs and shapes in Graph & cognition.
Where this fits, and where it doesn't
Whisper anchors the DER's identity at the device↔cloud IP boundary: the network endpoint your DERMS or aggregator backend authorizes. It is additive: it complements the roots of trust you already run and does not try to replace them, and it deliberately stops at the substation fence.
- IEEE 2030.5 / SunSpec-Kyrio
EndDevicecert (the SERCA→MCA→MICA root). The device's certificate key is the input to the derivation. Whisper adds a routable, DNSSEC/DANE-provable name on top of that private root of trust, and can DANE-pin the same cert your CSIP head-end already speaks. It complements that PKI; it does not replace it. - DERMS / VPP and OpenADR VTN head-ends. These consume the manufacturer's LFDI and authorize a bearer or a venID + JWT. Whisper gives them a forge-proof address to authorize instead of the token, and an off-switch the mandated PKI lacks: a drop-in for the identity the head-end already trusts, made revocable.
- ISO 15118 Plug&Charge / OCPP for EVSE. There the trust rides a hierarchical V2G root with fragile optional OCSP. Whisper adds an out-of-tenancy, DANE-verifiable identity per EVSE that any party can check without cross-signing, alongside your 15118 PKI, not inside its handshake.
- Where Whisper does not go. Not inside the IEC 61850 GOOSE/MMS substation bus, not the DNP3 outstation link, and not the ISO 15118 charging handshake at the connector. Whisper is the network identity of the endpoint on the IP fabric: the doorway, not the bus.
For mapping these identities to NERC CIP-013 / CIP-005 vendor-remote-access evidence, IEC 62351, CA Rule 21, EU NIS2 / NCCS, and NISTIR 7628, see NERC CIP · IEC 62351 · Rule 21. The Splunk, Microsoft Sentinel and OpenCTI connectors are shipped; STIX 2.1 over TAXII + E-ISAC machine-readable export is on the roadmap and labelled as such there. No specific operator or vendor is named, endorsed, or implicated as a breach victim anywhere in these docs; the abuse patterns cited are the public, cross-industry ones.
Next
- Grid-API-abuse cure: this identity, applied to the exact fleet-takeover / BOLA problem it was built for
- Platform integrations: dropping the
/128into IEEE 2030.5 / CSIP head-ends, DERMS & VPP, OpenADR, and SunSpec - DANE & TLSA: the byte-for-byte record that makes the address provable against the device key