Whisper · Docs
OT

Platform integrations

Whisper sits beside the OT stack you already run and anchors exactly one thing: a routable, verifiable identity at the asset/IP boundary. That's the layer where a reachable socket on a flat network looks identical to the real controller.

Everything below is a proposed integration pattern: our design, not a vendor endorsement. Every one is written the same way: Whisper complements the mechanism you have; it never replaces it. We do not touch Modbus, DNP3 or PROFINET on the wire, we do not sit in a PLC's command path, and we never join your OPC UA TrustList or terminate a SecureChannel. Those live on the fieldbus and inside the session, and they are already someone's job. Whisper's job is the network identity of whatever speaks across a conduit: a PLC, an RTU, an IED, an HMI, an engineering workstation, a historian, or a vendor's remote-access endpoint. It's expressed as an IPv6 /128 that DNSSEC, DANE and RDAP can prove and one call can revoke. No operator is named here as a breach victim; every pattern is described at the class level.

One spine under all six. Each integration below reuses the same shipped primitive: a deterministic /128 derived from a device's public key plus its native identifier (an OPC UA ApplicationUri, an 802.1AR IDevID serial, or a bare nameplate serial), passed as device_id (Asset & PLC identity), published with a DANE pin and an RDAP record, verifiable by anyone with no account. The integrations differ only in where in your stack that identity is bound and checked.

Anchor the boundary, not the bus

An OT environment carries several trust mechanisms, each correct for its own layer. The mistake is to imagine a new identity system has to displace one of them. It doesn't. Whisper is deliberately confined to the one place none of them cover: the moment a network endpoint claims to be a particular asset (a controller, a workstation, a sanctioned data consumer) and the receiver has only a reachable IP, a VLAN membership, or a private-CA certificate to go on.

Layer Owner / mechanism Whisper's role
In-plant fieldbus (Modbus / DNP3 / PROFINET) link trust; DNP3-SA pre-shared keys where present none: never on the wire or in the command path
OPC UA session security app-instance cert + local TrustList (GDS / CertificateManager) complements: publishes the ApplicationUri↔cert binding; TrustList stays
Device onboarding 802.1AR IDevID + BRSKI voucher complements: derives the /128 from the IDevID key; private half sealed
Asset ↔ network (IP) VLAN + firewall: trust = IP + topology anchors here: a publicly verifiable /128 the asset is, provable without your CA
four OT layers, four owners: Whisper anchors exactly one, and never the fieldbus In-plant fieldbus Modbus · DNP3 · PROFINET link trust: any reachable socket obeyed none never on the wire / command path OPC UA session app-instance cert + local TrustList publish the ApplicationUri↔cert binding complements the TrustList stays in place Device onboarding 802.1AR IDevID · BRSKI voucher derive the /128 from the IDevID key complements the private key stays sealed Asset ↔ network (IP) trust = IP + VLAN today a /128 the asset IS: provable without your CA ANCHORS HERE DNSSEC · DANE 3 1 1 · RDAP
Four OT trust layers, each correct for its own job. Whisper touches only the last (the asset↔network boundary, where trust today is just an IP and a VLAN) and never the fieldbus, the SecureChannel, or the PLC's command path.

Read the last row as the whole thesis: at the IP boundary, identity today is a claim, a source address on a segment. Whisper turns it into a network fact: the address itself, forward-confirmed in DNS, pinned in DANE, registered in RDAP, and revocable in one call.

OPC UA: publish the ApplicationUri↔certificate binding

OPC UA already does key-derived naming. Every application instance carries a globally-unique ApplicationUri, and OPC UA Part 6 §6.2.2 requires the application-instance certificate SAN to hold exactly one uniformResourceIdentifier equal to it. The stack enforces that binding at OpenSecureChannel / CreateSession: present a certificate whose URI ≠ the ApplicationUri and the session fails with BadCertificateUriInvalid. So the identity↔key binding is already cryptographic; it is just trapped in a local, per-site TrustList. OPC UA Part 2 §8.1.2 explicitly discourages public CAs so that no external party decides which applications are trusted, which is precisely why a peer operator, an integrator, or a regulator cannot verify your asset without being enrolled in your TrustList; revocation is a local CRL edit no one outside can see.

The integration is to publish that same binding under the public DNSSEC chain, adding nothing to OPC UA: pin the app-instance certificate's leaf key as a DANE-EE TLSA 3 1 1 under a DNSSEC-signed name for the asset. Now the ApplicationUri↔certificate binding OPC UA enforces privately becomes publicly, cross-org verifiable: no commercial CA, no change to your endpoints. The GDS / CertificateManager keeps doing onboarding, renewal, TrustList and CRL exactly as today.

# Pin the OPC UA endpoint's leaf key in DNSSEC-signed DNS. The binary port is 4840.
# No shared CA: a peer verifies the exact leaf, not a bundle you both have to trust.
dig +dnssec TLSA _4840._tcp.opcua-plc7.asset.<tenant>.agents.whisper.online
;; flags: qr rd ra ad          ← ad = DNSSEC-authenticated
;; _4840._tcp....agents.whisper.online. 300 IN TLSA 3 1 1 b653a4ef…fcb82d1d

# …and the whole binding (DNSSEC + DANE + RDAP) checked with no account, no TrustList.
whisper verify --trustless opcua-plc7.asset.<tenant>.agents.whisper.online
✓ DANE-EE (TLSA 3 1 1) leaf matches the asset's OPC UA application-instance cert key
✓ DNSSEC chain valid to the IANA root · RDAP: AS219419 · 2a04:2a01::/32

Complements the GDS / local TrustList, does not replace it. Whisper never joins your TrustList, never terminates a SecureChannel, and issues no application-instance certificate. It publishes the ApplicationUri↔key binding you already enforce, so anyone can confirm it from the DNSSEC root. See DANE & TLSA for the byte-for-byte record.

MUD (RFC 8520): the device's declaration, made enforceable

This is the sharpest OT fit. Under MUD (RFC 8520) a device already declares what it should talk to: a manufacturer-signed manifest of from-device-policy and to-device-policy ACLs, emitted over DHCP (options 161/112), an LLDP vendor TLV (type 127), or the id-pe-mud-url X.509 extension co-located with an 802.1AR IDevID. MUD's structural weakness: the manifest is only a hint, fetched from the manufacturer's domain and enforced by a local MUD manager at the nearest switch. A compromised device still reaches anything the local admin didn't block, and the binding is a spoofable URL, not a verifiable identity.

The integration binds that declaration to the asset's verifiable /128 and enforces it as default-deny egress governance where traffic actually leaves: cross-org, and checkable by anyone. Egress is source-bound to the asset's /128, so the manufacturer's declaration of intent becomes a cryptographic, enforced default rather than a suggestion at the nearest hop.

# The device declares its egress in MUD; Whisper enforces it as default-deny at the /128.
# This PLC may reach ONLY its historian, its controller, and the vendor OTA endpoint.
whisper policy set --agent 2a04:2a01:7a2::4840 \
  --default deny --allow historian.example-plant.example:4840,controller.line2.local,ota.vendor.example

# Per-asset firewall + a traffic budget + kill-switch: keyed to a verifiable identity, not a VLAN tag.
CALL whisper.agents({op:'firewall', args:{agent:'2a04:2a01:7a2::4840', deny:['0.0.0.0/0','::/0'], allow:['historian.example-plant.example:4840']}})
CALL whisper.agents({op:'budget',   args:{agent:'2a04:2a01:7a2::4840', max_mb_per_day:50}})

The honest edge. Egress governance changes who may reach and speak to an asset, and constrains what a governed asset may reach. It contains C2, exfil and lateral movement across the convergence bridge and the remote-access surface. It does not add authentication to Modbus, DNP3 or PROFINET on the wire, and it does not stop a purely-internal write by an attacker who already holds an OT-segment foothold: closing that last inch needs identity enforced in the command path, at the PLC, a protocol-aware broker-gateway, or the EWS. We say so before your assessor does.

Complements MUD, does not replace it. The manufacturer keeps authoring the manifest; Whisper pins it to a globally-verifiable identity and enforces it where traffic egresses. The full policy surface is on Egress governance; a runnable enforce-a-manifest recipe is on MUD egress · verify · attribute.

IEC 62443 zones & conduits: a conduit at the asset, not the VLAN

IEC 62443-3-3 makes segmentation mandatory (SR 5.1) and organises the plant into zones joined by conduits (the cross-trust channels between them, exactly where a portable, verifiable identity matters); 62443-4-2 CR 1.2 mandates unique device identification & authentication for every component. A per-/128 egress allow-list is a conduit at asset granularity (a micro-segment at the asset, not the VLAN), keyed to a cryptographically verifiable identity rather than an IP or a VLAN tag. Compromise one asset and the blast radius is that asset, not the flat segment.

segment at the asset, not the VLAN: an identity-keyed conduit per device Flat VLAN zone trust = IP + VLAN · one blast radius PLC RTU IED HMI EWS GW one foothold inherits the whole segment op:firewall op:policy Per-/128 conduits one micro-segment per asset, identity-keyed PLC /128allow-list only RTU /128allow-list only IED /128allow-list only HMI /128allow-list only EWS /128allow-list only GW /128allow-list only each reaches only its own allow-list
The same six assets, two segmentation models. A VLAN is one trust zone shared by all of them; a per-/128 conduit is a micro-segment at each asset, keyed to a verifiable identity and enforced with op:firewall, additive to your 62443 zones, not a replacement for them.
# A conduit at the asset: this IED reaches ONLY its historian (OPC UA :4840) and controller (DNP3 :20000).
CALL whisper.agents({op:'firewall', args:{agent:'2a04:2a01:7a2::4840',
  deny:['0.0.0.0/0','::/0'],
  allow:['historian.example-plant.example:4840','controller.line2.local:20000']}})

And nothing is issued in the dark: every mint and every revoke lands in a public, append-only Merkle transparency log (Ed25519-signed and anchored to Bitcoin via OpenTimestamps) that you and your assessor can replay as a non-repudiable issuance/revocation trail. (Honest status: tamper-evident and Bitcoin-anchored today; independent third-party witnessing is the next step, and the log already speaks the witness protocol.)

Complements your 62443 zones & conduits, does not replace them. Whisper supplies the unique network identifier (the CR 1.2 identity half) and the identity-keyed conduit (SR 5.1), additive to your SL program. The asset still does its own mutual-auth handshake; we make identity globally verifiable and revocable, we do not claim end-to-end CR 1.2 authentication. The full mapping is on IEC 62443 · EU CRA · TSA.

IEEE 802.1AR IDevID & BRSKI: the birth certificate, onto the network

This is the shipped spine the other five build on. An 802.1AR IDevID (or a TPM or in-vehicle-grade secure element) is a device's hardware birth certificate: a key generated on the silicon whose private half never leaves it. BRSKI (RFC 8995) turns that IDevID into an operator-issued LDevID through a pledge → registrar → MASA voucher (RFC 8366) exchange. Whisper derives the asset's /128 from that device's public SubjectPublicKeyInfo plus its serial (or ApplicationUri), bridging the identity plane onto the network plane at the same onboarding moment. The private key stays sealed; only the public SPKI is ever an input.

The derivation is deterministic and tenant-bound: the same key and identifier always yield the same /128, the mapping is unlinkable to outsiders so a fleet can't be enumerated from its addresses, and the result is DNSSEC-anchored, DANE-EE 3 1 1 pinned, and RDAP-registered the instant it's minted.

# Provision the /128 for an asset from the key it already holds at onboarding + its native id.
# identity_public_key is the device's PUBLIC SPKI (base64): the IDevID / TPM key.
CALL whisper.agents({op:'connect', args:{
  tier:'wireguard',
  identity_public_key:'<base64 SPKI of the IDevID / TPM key>',
  device_id:'urn:example-plant:line2:PLC7:server'   // ApplicationUri, IDevID serial or nameplate serial
}}) YIELD op, ok, status, result, error
RETURN op, ok, status, result, error

Send it with stock tools. The control plane is one HTTP endpoint, and the heredoc keeps the single-quoted Cypher literals intact so it runs as-is:

curl -s https://graph.whisper.security/api/query \
  -H "X-API-Key: whisper_live_xxx" \
  -H 'content-type: application/json' \
  --data @- <<'JSON'
{"query":"CALL whisper.agents({op:'connect', args:{tier:'wireguard', identity_public_key:'<base64 SPKI>', device_id:'urn:example-plant:line2:PLC7:server'}}) YIELD op, ok, status, result, error RETURN op, ok, status, result, error"}
JSON
{ "ok": true, "status": "created",
  "result": { "address": "2a04:2a01:7a2::4840",
    "fqdn": "opcua-plc7.asset.<tenant>.agents.whisper.online",
    "wireguard": { /* peer, keys, allowed-ips */ } } }

The behaviour is honest and predictable, which is the point:

Re-provision with…Result
the same key + device_id200: the same /128 returns (idempotent)
a different device_id on the same tenant's key409: the identity is already bound; no silent rebind
a non-string device_id400: a clear input error, never an opaque 500

Tear it down worldwide at DNS-TTL speed with one call. The /128, its PTR, and its DANE pin all go together:

CALL whisper.agents({op:'revoke', args:{agent:'2a04:2a01:7a2::4840'}})

Complements the IDevID / BRSKI, does not replace it. The birth certificate stays exactly where it was born: the private key never leaves the secure element, because Whisper only ever consumes the public SPKI. The full derivation, tenant-unlinkability property and DANE mechanics are on Asset & PLC identity.

OT visibility platforms: consume the inventory, feed the SOC

The OT-visibility platform class (passive discovery, deep OT-protocol inventory, and process-aware anomaly detection) is excellent at exactly what Whisper deliberately does not do. These platforms are allies, not rivals. There are two clean handoffs, and neither asks you to move a single sensor.

And op:lookups is a reconnaissance tripwire the platforms can't give you: because every asset's name resolves through Whisper's own authoritative DNS and RDAP, you can ask who resolved or RDAP-queried an asset's identity (someone enumerating your plant) before the write lands, not in the post-mortem afterward.

# Consume an asset from your visibility platform's inventory → give it a verifiable /128.
# device_id = whatever native id the inventory already carries (ApplicationUri / IDevID serial / nameplate).

# Feed attribution back to the SOC: name the operator behind a rotating remote-access egress.
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(\"45.83.x.x\")"}' | jq .
# → operator clustered across clouds by shared ASN / hosting / cert lineage; remote-access pool collapsed by JA4

# Who has been enumerating this asset's identity: resolving its PTR/AAAA/TLSA or hitting its RDAP object?
CALL whisper.agents({op:'lookups', args:{agent:'2a04:2a01:7a2::4840', window:'24h'}})

Complements OT-visibility platforms, does not replace them. Whisper does no OT-protocol visibility, no asset discovery, and no anomaly detection. That ground stays theirs. We consume their inventory as an identity input and feed cross-org attribution back to their SOC. More on the attribution verbs is in Graph & cognition.

The SIEM feed: Splunk, Sentinel & OpenCTI today; STIX/TAXII next

Identity, egress and attribution evidence should land where your OT SOC already looks. The Splunk connector is shipped & live: a signed, replayable JSON evidence line mapped to CEF / ECS fields, so an asset's own outbound activity (op:logs) and who queried its identity (op:lookups) both stream into your existing dashboards and correlation searches.

The Microsoft Sentinel connector and OpenCTI integration ship today. STIX 2.1 over TAXII is on the roadmap, together with sector-ISAC (E-ISAC / WaterISAC) machine-readable export. We label these honestly so you can plan against them, not around them.

# Shipped & live: the Splunk connector maps a signed, replayable evidence line → CEF / ECS.
# The evidence is the same whether it feeds a dashboard, a correlation search, or an audit.
{ "identity": "2a04:2a01:7a2::4840", "event": "egress.deny",
  "dst": "scan.example:502", "policy": "default-deny", "sig": "ed25519:…" }
# → cef: CEF:0|Whisper|OT|1|egress.deny|Egress denied|5|src=2a04:2a01:7a2::4840 dst=scan.example dpt=502

Shipped today vs proposed

Honesty about what runs matters more here than anywhere. The identity primitive and its control plane under every integration are live and provable right now; the integration guides themselves are proposed patterns for wiring that primitive into each platform.

Building blockStatus
Deterministic /128 from a device's public key + device_id (ApplicationUri / IDevID serial / nameplate)shipped, live
Provision via the control plane (op:'connect', WireGuard tier)shipped, live
Keyless verify: whisper verify --trustless, /verify-identity, dig -x, RDAPshipped, live
MUD-style egress governance: op:policy / op:firewall / op:budgetshipped, live
Revoke: /128 + PTR + DANE torn down at DNS-TTL speedshipped, live
op:lookups (who queried this identity) + the Merkle transparency logshipped: log is tamper-evident + Bitcoin-anchored, not yet independently witnessed
Attribution graph over the public API (CALL whisper.identify(…))shipped, live
The Splunk connector (signed JSON → CEF / ECS)shipped, live
A first-class typed --application-uri / --mud CLI flagproposed: provision via the control-plane call today
STIX 2.1 / TAXII · sector-ISAC exportproposed / roadmap
The six integration guides on this page (OPC UA, MUD, 62443, 802.1AR/BRSKI, OT-visibility, SIEM)proposed: our design, not a vendor endorsement
i

The --application-uri / --mud CLI flags are not shipped yet. Asset provisioning today goes through the control-plane call in the 802.1AR section above, which is live. The shipped CLI verbs are whisper verify --trustless, whisper create --register, whisper kill --revoke, whisper policy, and whisper logs. See CLI & one-command.

Next