Verify · attribute · govern
Six copy-paste recipes put a forge-proof, revocable network identity under a medical device and a FHIR endpoint. Bind it to the Endpoint.identifier it already carries, prove it keyless, DANE-pin your UDAP endpoint certificate to public DNSSEC, back-trace whoever is driving a suspicious API session, govern exactly what a device may reach, and see who is enumerating your fleet. Each runs today against shipped primitives.
They share one primitive: a routable IPv6 /128 that a device or endpoint derives from a key it already holds, DNSSEC-signed and DANE-pinned so any relying party can verify it and nobody can forge it. Everything below is built from shipped parts: the device /128, keyless verify, the attribution graph, per-device egress governance, the reverse-observability op:lookups, the Merkle transparency log, and one-call revoke. Where a step is a pattern you assemble rather than a single command, or a connector still on the roadmap, it says so in plain words.
What's shipped, stated honestly. The device/endpoint /128 derivation, keyless verify / RDAP, the attribution graph (whisper.identify), per-device egress governance (policy · firewall · budget · revoke), the reverse-observability op:lookups, and the Merkle transparency log are all live. Two caveats these recipes are written around: there is no first-class --fhir-endpoint or --udi CLI flag yet, so provisioning is shown via the control-plane API (which is live) with the Endpoint.identifier or FDA UDI passed as the generic device_id; and the SIEM/threat-intel export connectors named at the end are roadmap beyond Splunk, which ships. Whisper anchors the IP / DNS / transport boundary: it is not on the clinical bus (HL7v2, unauthenticated DICOM, Modbus), not inside a device's own key store, and it does not fix a FHIR BOLA in the application's authorization. It complements segmentation, device patching, and protocol-level auth; it never replaces them. Each recipe names exactly where it stops.
The shared primitive: an identity a device derives, not one you hand it
A FHIR endpoint, an EHR-facing gateway, or a connected medical device already carries a key: the key behind its UDAP server certificate, a secure-element or TPM key, or, for an ISO/IEEE 11073 point-of-care device, a hardware key named by an EUI-64. Whisper takes only its public SubjectPublicKeyInfo (SPKI) and, together with the Endpoint.identifier (or the FDA UDI device identifier, or a DICOM AE Title) as a domain separator, deterministically derives a /128 under 2a04:2a01::/32 (AS219419). The private key never leaves the device; the server only ever computes a public address.
The Endpoint.address in FHIR is already a URL (DNS-addressable by construction), but the FHIR Endpoint resource carries no key, signature, or certificate: its own trust model is "None", delegated to TLS and out-of-band UDAP. The derivation below turns that name into an identity with four properties the resource itself lacks:
- Deterministic & idempotent: the same device key +
Endpoint.identifieralways yields the same/128. Re-provisioning a replacement communication module for the sameDevicereturns the same address; there is no registry to keep in sync. - Tenant-bound & fleet-unlinkable: the derivation folds in your tenant, so the same device under two organizations yields two unrelated
/128s. No one can link a unit across HDOs or HIEs by address suffix, and there is no enumeration oracle. - Forge-proof: the
/128is DANE-EE3 1 1-pinned to that device's key and has DNSSEC-signed reverse DNS. A cloned device with a different key derives a different address and can't present the pinned key. - Revocable worldwide: one control-plane call tears the
/128, its PTR, and its DANE pin down everywhere at DNS-TTL speed. That's the cross-organization off-switch a community CRL/OCSP scoped to one trust anchor never gave you.
/128, and the off-switch a private community trust anchor can't give a counterparty outside it.Because the address is bound to the device's key and its identifier, the identifier alone yields nothing. You cannot go Endpoint.identifier → /128 without the key, and RDAP / reverse-DNS return the registry object, never a directory of your fleet. One honest limit up front: the identity is only as forge-proof as the device's key custody (on an end-of-life device with no TPM or secure element, protect the key accordingly). Every check in the recipes below that doesn't provision is keyless: no account, just DNS and TLS any counterparty already has.
Recipe 1: Bind a device or endpoint to its FHIR Endpoint.identifier
Give a FHIR endpoint (or a connected medical device) the network identity it should have been born with, derived from the key it already holds and named by the Endpoint.identifier that already flows through every TEFCA / RCE directory entry. One call; the reply is the address, and a stock dig confirms the name.
Boundary. This complements the FHIR Endpoint resource, the UDAP server certificate, and FDA UDI/GUDID. It does not replace them or touch the clinical bus (HL7v2, DICOM, Modbus). It takes the public half of the device's existing key and makes it addressable, publicly verifiable, and revocable. The /128 is only as forge-proof as the key store it derives from.
Pass the Endpoint.identifier (or a device's FDA UDI device identifier) as the generic device_id. Re-running with the same device key + identifier returns the same /128, which makes it idempotent and safe to run from a provisioning loop:
# Bind a FHIR endpoint to the Endpoint.identifier it already carries. device_id = the identifier.
# Re-running with the same device key + identifier returns the SAME /128 (idempotent).
curl -s https://graph.whisper.security/api/query \
-H "X-API-Key: whisper_live_xxx" \
-H "content-type: application/json" \
-d '{"query":"CALL whisper.agents({op:'"'"'connect'"'"', args:{tier:'"'"'wireguard'"'"', identity_public_key:'"'"'<base64 SPKI of the UDAP server-cert key>'"'"', device_id:'"'"'urn:oid:2.16.840.1.113883.3.7204:endpoint:ehr-prod'"'"'}}) YIELD op, ok, status, result, error RETURN op, ok, status, result, error"}' | jq .
{ "op":"connect", "ok":true, "status":200,
"result":{ "address":"2a04:2a01:7d2::b19",
"name":"ep-3f2504e0.fhir.example-hie.whisper.online",
"dane":"3 1 1", "dnssec":"signed", "wireguard":"<peer config>" } }
# For a physical device, pass its FDA UDI device identifier (the GUDID DI) instead:
# args:{tier:'wireguard', identity_public_key:'…', device_id:'00889842179897'} # UDI DI
# or a DICOM node's AE Title, or an ISO/IEEE 11073 EUI-64 (any native identifier).
Confirm the /128 and its name from the other side, keyless. The reverse DNS is forward-confirmed (PTR ⇄ AAAA), so nothing but dig is required:
dig +short -x 2a04:2a01:7d2::b19
ep-3f2504e0.fhir.example-hie.whisper.online.
# …and the forward AAAA resolves straight back, the round trip that makes it forge-proof:
dig +short AAAA ep-3f2504e0.fhir.example-hie.whisper.online
2a04:2a01:7d2::b19
The mint is not issued in the dark. Every /128 minted and every one revoked lands in a public, append-only Merkle transparency log, so you and an auditor can replay the full issuance history of your fleet. That's the kind of asset-identity trail a HIPAA network map and an FDA §524B postmarket program both need:
# The identity's ordered lifecycle (mint, any rotations, revoke), keyless:
curl -s https://whisper.online/ip/2a04:2a01:7d2::b19/transparency
A supplied identifier is checked against a reused identity: the same device key with a different device_id on your tenant is a 409, and a non-string device_id is a clear 400. That's liberal in what it accepts, strict and unambiguous in what it commits. Honest status of the ledger: it is tamper-evident, Ed25519-signed, and Bitcoin-anchored via OpenTimestamps today; independent third-party witnessing is the next step. It already speaks the C2SP tlog-witness protocol so any external witness can co-sign. A first-class typed --fhir-endpoint / --udi argument is on the roadmap; today the identifier rides the generic device_id, which is shipped.
Recipe 2: Prove a device's identity, keyless
Once bound, any counterparty (a QHIN before it queries, an EHR before it accepts a report, a device before it trusts the server it is reporting to) proves the endpoint or device is real without an account, without a shared CA list, and without trusting Whisper as an authority. The proof re-derives against the IANA DNSSEC root.
Boundary: the honest last inch. This authenticates the endpoint's network identity at the IP/transport boundary. It kills a stolen static credential: a lifted UDAP/SMART token or a hard-coded key buys nothing, because the identity is a network fact bound to a key, not a bearer string that replays from another host. It does not authenticate the caller (that stays with SMART / OAuth), does not fix a FHIR BOLA in the application's own authorization, and does not stop an HL7v2 injection or an unauthenticated DICOM C-STORE between two nodes on the same segment. Those are segmentation and protocol-auth problems that still need in-path enforcement. Whisper shrinks who can reach the endpoint and attributes them; it does not patch the protocol.
The trustless check walks the full chain (DNSSEC to the IANA root, the DANE-EE pin, and the transparency-log entry) and prints exactly what it trusted:
# Prove any device/endpoint identity, trustless: re-derived against the IANA DNSSEC root,
# with no Whisper API trusted as an authority anywhere in the chain.
whisper verify --trustless 2a04:2a01:7d2::b19
dnssec pass DNSSEC-root AAAA, PTR and TLSA(3 1 1) all DNSSEC-validated to the IANA root
dane pass DNSSEC-root served leaf SPKI-SHA256 == TLSA pin
ledger pass DNSSEC-root transparency-log entry present, signature verifies
CRYPTOGRAPHICALLY PROVEN · trust anchor: DNSSEC root (IANA) + DANE-EE · Whisper API NOT trusted
The same fact is reachable with tools already in every ops toolbox. One keyless HTTPS call, or plain dig, gets you there:
# Is this address a real, DANE-anchored device identity? One keyless call, no install:
curl -s https://whisper.online/verify-identity/2a04:2a01:7d2::b19
{"is_whisper_agent":true,"dane_ok":true,"jws_ok":true,
"evidence":{"address":"2a04:2a01:7d2::b19",
"ptr":"ep-3f2504e0.fhir.example-hie.whisper.online.",
"forward_aaaa":"2a04:2a01:7d2::b19"}}
# A rogue endpoint or cloned device, with no registered /128 for its key or DANE pin to present:
curl -s https://whisper.online/verify-identity/2a04:2a01::1
{"is_whisper_agent":false,"detail":"no Whisper agent identity anchors this address"}
Two counterparties in a TEFCA exchange can now confirm each other with nothing but DNS and TLS: the layer where the network answers "who is this, provably," which is exactly where Endpoint.address lives and where the FHIR resource itself carries no proof.
Recipe 3: DANE-pin your UDAP / FHIR endpoint cert to public DNSSEC
UDAP already proves your FHIR endpoint's identity to your community: the base URL SHALL equal the server's {baseURL} and SHALL match a uniformResourceIdentifier entry in the certificate's SubjectAltName, and /.well-known/udap returns signed_metadata, a JWS signed by the server key, with its chain in the x5c header. The gap: that proof is rooted in a private, community-scoped trust anchor. A relying party can only verify it if it was pre-provisioned with your community's CA: a TEFCA anchor, a DirectTrust anchor, a state-HIE anchor. Publish a DNSSEC-signed DANE TLSA record that pins the same certificate, and any relying party (even one outside your community, with no anchor pre-provisioned) verifies the base-URL↔cert binding against the IANA DNS root. That closes the base-URL↔cert spoofing gap UDAP can only assert privately.
Boundary. This complements UDAP. It does not replace its Dynamic Client Registration, tiered OAuth, JWT client auth, or your community trust anchor, and it authenticates the endpoint host, not the caller. It publishes, in open DNS, the same cert-to-URL binding UDAP asserts inside the community, and makes it revocable at DNS-TTL: a second, orthogonal, publicly rooted proof beside the community CA. It does not touch SMART app authorization or a FHIR BOLA.
C inside a private community anchor; a DNSSEC-signed TLSA 3 1 1 pins the same C in open DNS, so a relying party outside the community verifies the binding against the IANA root.The endpoint host's /128 (provisioned exactly as in Recipe 1, but with identity_public_key set to the SPKI of your UDAP server certificate's key) is DANE-pinned to that certificate automatically. From then on, the pin equals the SPKI of the very cert UDAP signs its metadata with, and any party can cross-check the three facts line up:
# 1) What UDAP presents to the community (the signed_metadata leaf is cert C):
curl -s https://fhir.example-hie.org/r4/.well-known/udap | jq -r .signed_metadata
eyJ4NWMiOlsiTUlJ…"]} # its x5c[0] leaf is cert C; iss == the FHIR base URL
# 2) What Whisper publishes to everyone (the DNSSEC-signed DANE pin of the SAME leaf C):
dig +short TLSA _443._tcp.ep-3f2504e0.fhir.example-hie.whisper.online
3 1 1 b653a4ef…fcb82d1d
# 3) The live TLS leaf, which must equal BOTH the TLSA pin and the UDAP x5c leaf:
openssl s_client -connect fhir.example-hie.org:443 </dev/null 2>/dev/null \
| openssl x509 -pubkey -noout | openssl pkey -pubin -outform der \
| openssl dgst -sha256 # == the TLSA pin above == the UDAP signed_metadata leaf SPKI
A rogue server answering on that name, or a certificate mis-issued under some community anchor, fails immediately. It cannot present a leaf whose SPKI matches the DNSSEC-signed TLSA pin. And if the key is burned, one revoke drops the pin worldwide at DNS-TTL, a kill-switch that reaches every relying party at once, not just the ones inside your CRL/OCSP scope:
whisper verify --trustless ep-3f2504e0.fhir.example-hie.whisper.online
dane pass DNSSEC-root served leaf SPKI-SHA256 == TLSA pin (== UDAP x5c leaf)
CRYPTOGRAPHICALLY PROVEN · base-URL ↔ cert binding verified without your community anchor
Recipe 4: Back-trace a suspicious API session
Detection tools tell you that a FHIR or UDAP client is hammering your endpoint oddly. When the source rotates across clouds and residential proxies (the pattern behind third-party-vendor compromise, the origin of 41% of 2024 healthcare breaches), they lose who at the firewall. The attribution graph doesn't: it fingerprints the operator, not the disposable last IP. This is the keyed half, and it is exactly the "verify who is asking" that TEFCA itself names as an open problem. Pass the suspicious egress address to whisper.identify over the public graph API.
Boundary. This is an enrichment query over Whisper's internet-infrastructure graph (BGP, DNS, WHOIS, TLS, hosting, and threat-intel), not a tap on your clinical network. It complements your IoMT sensor and SIEM; the egress IP is the one thing it never relies on. It attributes the operator; it does not, by itself, block them.
JA4 client fingerprint collapses the residential swarm: the cross-organization view a single-hospital sensor structurally can't see.The call itself is the graph API, since there is no whisper identify CLI verb. Passing the address to whisper.identify over POST https://graph.whisper.security/api/query is the interface:
# Who really operates the client behind a suspicious FHIR/UDAP session? The graph API.
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> · seen across AWS / GCP / Azure
residential swarm collapsed by JA4: same tooling, 41 exit IPs → 1 operator
evidence: reproducible, replayable JSON for your SOC and an auditor
Cluster the rotation into one genealogy, then express the exchange-scale question (one source touching N distinct endpoint identities in a window) as read-only Cypher rather than a ticket:
# Cluster the rotating egress into one infrastructure genealogy, and timeline it:
curl -s https://graph.whisper.security/api/query -H "X-API-Key: whisper_live_xxx" \
-H "content-type: application/json" \
-d '{"query":"CALL whisper.origins(\"34.90.0.0/16\") YIELD asn, prefix, first_seen RETURN asn, prefix, first_seen"}' | jq .
# whisper.walk(node, depth) expands the genealogy; whisper.history() gives the timeline.
Recipe 5: Govern a device's egress
An identity you can prove is also one you can fence. An infusion pump, an imaging modality, or an EHR gateway should talk to its FHIR server, its QHIN, and its vendor's update host, and nothing else. So make that the policy, cap what it can move, and keep the one-call kill-switch ready. Because egress source-binds to the device's own /128, these controls apply to the device, not to a fragile IP allowlist, and they work even on an agentless or end-of-life device that could never take a NAC client.
Boundary. This governs the device's internet-side egress via the graph-first resolver and source-bound egress. It is an L3 allow-list: additive and availability-safe, adding no inline chokepoint on the clinical bus. It maps directly to the HIPAA Security Rule NPRM's network-segmentation ask, the HHS CPG segmentation goal, and access control at §164.312(a). What it does not do is stop a same-segment, unauthenticated clinical-protocol exchange between two nodes on the ward LAN; that remains a segmentation + protocol-auth problem. It shrinks who a device can reach and cuts its C2/exfil path; it does not become the ward firewall.
revoke that cuts a compromised device off worldwide, an L3 segment even a device that can't run an agent can be given.Set the resolution policy to default-deny and allow only the names the device legitimately needs, with the CLI or over the control plane with op:policy:
# Default-deny the device's egress; allow only its FHIR server and its QHIN.
whisper policy set --agent 2a04:2a01:7d2::a03 \
--default deny --allow fhir.example-hie.org,qhin.example-network.org
# The same, over the control plane (op:policy), allowing by name or subdomain:
curl -s https://graph.whisper.security/api/query -H "X-API-Key: whisper_live_xxx" \
-H "content-type: application/json" \
-d '{"query":"CALL whisper.agents({op:'"'"'policy'"'"', args:{agent:'"'"'2a04:2a01:7d2::a03'"'"', default:'"'"'deny'"'"', allow:['"'"'fhir.example-hie.org'"'"','"'"'qhin.example-network.org'"'"']}})"}'
Tighten it further with a per-device firewall by host, cidr or port, cap what the device can move with a budget, and keep the kill-switch one verb away:
# Per-device firewall (op:firewall), allowing the vendor update host on 443 and denying all else:
curl -s https://graph.whisper.security/api/query -H "X-API-Key: whisper_live_xxx" \
-H "content-type: application/json" \
-d '{"query":"CALL whisper.agents({op:'"'"'firewall'"'"', args:{agent:'"'"'2a04:2a01:7d2::a03'"'"', rules:[{allow:'"'"'host'"'"', host:'"'"'updates.example-vendor.com'"'"', port:443},{deny:'"'"'all'"'"'}]}})"}'
# Budget + kill-switch (op:budget), capping egress volume and tripping the switch past the cap:
curl -s https://graph.whisper.security/api/query -H "X-API-Key: whisper_live_xxx" \
-H "content-type: application/json" \
-d '{"query":"CALL whisper.agents({op:'"'"'budget'"'"', args:{agent:'"'"'2a04:2a01:7d2::a03'"'"', egress_mb_per_day:20, on_exceed:'"'"'kill'"'"'}})"}'
# Cut a compromised device off worldwide in one call (op:revoke), no re-imaging, no truck roll:
whisper kill --revoke 2a04:2a01:7d2::a03 # worldwide, at DNS-TTL
After the revoke, every keyless check from Recipe 2 flips to is_whisper_agent:false for that address within the DNS TTL: no CRL to distribute, no per-vendor blocklist to push, no fleet-wide firmware flash. Containment is one call, and it lands in the transparency log, the postmarket-containment evidence FDA §524B(b)(1) asks you to be able to demonstrate.
Recipe 6: See who enumerated your fleet
The kill-chain starts with reconnaissance: someone resolving and RDAP-querying your endpoint and device identities to map the fleet before the session. A stale TEFCA/RCE or NDH directory makes it easy: a listed FHIR base URL invites a walk of every endpoint behind it. Because every identity's name resolves through Whisper's own authoritative DNS and RDAP, the owner sees exactly who looked, a tripwire the community directory never gave you. This is reverse observability: not the device's own outbound (op:logs), but who has been checking it.
Boundary. op:lookups reports resolution and RDAP accesses against your identities' authoritative records: the PTR / AAAA / TLSA queries and /ip reads. It is an early-warning signal, not a claim to see traffic inside someone else's network; pair it with Recipe 4 to turn a suspicious source into an attributed operator.
op:lookups as an early warning, not a post-mortem.Ask who has been checking a single endpoint's identity (keyless, for that address) or the whole fleet with your key:
# Who resolved or RDAP-queried this endpoint's identity? A recon tripwire, keyless per-address:
curl -s https://whisper.online/ip/2a04:2a01:7d2::b19/lookups
{"address":"2a04:2a01:7d2::b19","window":"24h",
"lookups":[{"kind":"PTR","count":6},{"kind":"TLSA","count":2},
{"kind":"rdap","count":3}]}
# Fleet-wide, with your key (op:lookups): the single source walking your whole directory:
curl -s https://graph.whisper.security/api/query -H "X-API-Key: whisper_live_xxx" \
-H "content-type: application/json" \
-d '{"query":"CALL whisper.agents({op:'"'"'lookups'"'"', args:{scope:'"'"'fleet'"'"', window:'"'"'60s'"'"'}})"}' | jq .
source 34.90.x.x: resolved 512 distinct endpoint identities in 60s ⚠ enumeration
Feed that source straight into Recipe 4's whisper.identify and the anonymous recon becomes an attributed operator, before a single record is queried.
Where each recipe stops and what's roadmap
Honest scoping, one row per recipe. Whisper anchors the IP / DNS / transport boundary; the clinical bus, the device's own key store, and the application's authorization stay exactly where they are.
| Recipe | Complements | Does not touch / replace |
|---|---|---|
| Bind to its identifier | FHIR Endpoint resource, UDAP server cert, FDA UDI/GUDID |
the device's own key custody; the clinical bus (HL7v2 / DICOM / Modbus) |
| Prove keyless · DANE-pin UDAP | the UDAP community CA, /.well-known/udap signed_metadata |
UDAP DCR / tiered OAuth / JWT client auth; SMART app authZ; a FHIR BOLA |
| Back-trace · Lookups | your IoMT sensor, SIEM and threat-intel; TEFCA "verify who is asking" | a tap on your clinical network; it enriches, it doesn't monitor the LAN |
| Govern device egress | HIPAA NPRM segmentation, HHS CPG, §164.312(a), IEC 62443 FR2 | an inline clinical chokepoint; a same-segment unauthenticated DICOM / HL7v2 exchange |
Roadmap, clearly labelled. Streaming this evidence into a SIEM ships today for Splunk, Microsoft Sentinel and OpenCTI (signed JSON → CEF/ECS). A STIX 2.1 over TAXII feed and a Health-ISAC machine-readable export for sharing revocation and attribution evidence are proposed, not yet available. And the first-class typed --fhir-endpoint / --udi arguments are roadmap: provision via the control-plane API shown above, passing the identifier as the generic device_id, which is live. The transparency log is tamper-evident, Ed25519-signed and Bitcoin-anchored today; independent witnessing is the next step. Nothing on this list is required for the six recipes; they run on shipped primitives alone.
Next
- Device & FHIR-endpoint identity: the full derivation the
/128above comes from, key +Endpoint.identifierto address - Device/API-abuse cure: these primitives applied to the exact stolen-credential / FHIR-BOLA / rogue-endpoint problem they were built for
- DANE & TLSA: the
3 1 1pin every check here rests on, byte for byte - FDA 524B · HIPAA · MDR: where these recipes map into §524B, HIPAA-NPRM and MDR evidence