Whisper · Docs
Health

Device & FHIR-endpoint identity

Give a medical device or a FHIR endpoint a routable IPv6 /128 derived from the public key it already holds, named by its Endpoint.identifier or its FDA UDI. The address is the endpoint: forge-proof, tenant-private, DNSSEC-anchored, DANE-EE pinned, and revocable worldwide in one call.

This is the spine of the health vertical, and it is shipped and live. Everything else (the device/API-abuse cure, the FHIR·UDAP·TEFCA·UDI integration guides, the FDA §524B and HIPAA evidence) builds on the one idea below: an endpoint's network address stops being a label a directory publishes on faith and a proxy can rotate, and becomes a cryptographic fact only that endpoint's key can stand behind. It complements UDAP, SMART, and TEFCA; it never replaces them.

Shipped & live. Deriving a device or endpoint /128 from the public key it already holds (with the Endpoint.identifier or the UDI as the domain separator) is in production today. Provision one with the control-plane call below and verify it from the DNSSEC root with tools already on your machine. A first-class typed --endpoint / --udi flag is on the roadmap; the generic device_id path is live now.

Two tiers, per Postel's Law. With no API key anyone (a QHIN allow-listing a peer, an auditor, a suspicious relying party) can verify an endpoint's identity from stock tools (dig, curl, RDAP), because the identity half is public by design. With your key you provision and govern: mint the /128, DANE-pin the endpoint cert, source-bind egress, pull the logs, see who checked it, and revoke it. Verification never needs an account; the control plane does.

The address is the endpoint

Every layer of the health stack already carries an identifier, and most now carry a key. What none of them carry is a binding of identifier ↔ key ↔ routable address that anyone can verify at the address itself. The binding always lives somewhere private.

The seam is identical at every layer: a stable identifier, increasingly a key, but a binding to a routable address that is private, out-of-band, and not self-verifying at the address. Whisper closes it by making the network address itself the credential. The endpoint gets a real, routable /128 out of 2a04:2a01::/32 (announced by AS219419) that is a deterministic function of the key it already holds and its Endpoint.identifier or UDI. Because the address is derived from a key only that endpoint holds, you cannot present an endpoint identity whose key you don't have: a spoofed Device.url, a rogue aggregator replaying a token, or one IP claiming to be a thousand devices each becomes a DNSSEC/DANE inconsistency any verifier catches for free.

already at the endpoint public · verifiable · revocable: what Whisper adds Endpoint / device key SPKI · UDAP cert / 802.1AR / TPM Endpoint.identifier | UDI private key sealed on-device public SPKI + id /128 2a04:2a01:f8e7:ca11: c0de:f41d:9a3d:71b2 routable · tenant-bound DNSSEC + DANE-EE 3 1 1 A name anyone can verify whisper verify --trustless RDAP-registered · DNSSEC to the IANA root our own API is not in the trust path op:'revoke' → gone worldwide at DNS-TTL
The FHIR Endpoint.identifier or FDA UDI names an endpoint the private UDAP anchor can only vouch for in-community; Whisper binds it to a routable, publicly verifiable /128 derived from the key the endpoint already holds: DNSSEC-anchored, DANE-EE 3 1 1 pinned, and revocable worldwide in one call.

How the derivation works

The /128 is not drawn from a pool and written into a database. It is computed, the same way on every node, from inputs the endpoint already has. Three things go in:

Input What it is Where it lives
Device / endpoint public key the SubjectPublicKeyInfo (SPKI) of the key the endpoint holds: the UDAP server cert's key, an 802.1AR IDevID, a TPM, or a secure-element key the public half is submitted; the private key never leaves the device
Endpoint.identifier (or UDI DI) the FHIR Endpoint.identifier / UDAP base URL for an endpoint, or the FDA UDI Device Identifier for a physical device (the native, stable id) submitted with the request; the public index (device_id)
Component serial (optional) a per-component domain separator, so one machine can hold several addressable identities (e.g. a modality and its DICOM AE, or a gateway and the legacy devices behind it) optional; omit it for a single per-endpoint 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 organization:

# inputs -> a stable, forge-proof interface identifier
derive( endpoint public key,  Endpoint.identifier | UDI [, serial],  your org )  -->  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:

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 endpoint'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 endpoint submits only its public SPKI: the same public half of the UDAP / 802.1AR / 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 endpoint's private key. The device proves ownership later by presenting its own key against the DANE pin.

Provision a device or endpoint identity

Provisioning is one control-plane call: whisper.agents with op:'connect', tier:'wireguard', the endpoint's public SPKI, and its identifier as device_id. It returns the deterministic /128 and a ready WireGuard configuration so the endpoint'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 endpoint key>',
  device_id:           'https://fhir.example-hdo.org/r4'   // the Endpoint.identifier / UDAP base URL
  // device_id: '00860001234567890'   // …or a physical device's FDA UDI (DI)
  // serial: 'AE-CT01'                 // 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:'https://fhir.example-hdo.org/r4'}}) 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 endpoint 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:f8e7:ca11:c0de:f41d:9a3d:71b2",   // the deterministic /128
    "fqdn":               "ep-c0def41d.fhir.<tenant>.agents.whisper.online",
    "server_public_key":  "…",
    "endpoint":           "…:51820",
    "dns":                "2a04:2a01:0:53::53",
    "wireguard_config":   "[Interface]\nAddress = 2a04:2a01:f8e7:ca11:c0de:f41d:9a3d:71b2/128\n…"
  },
  "error": null
}

Drop the returned wireguard_config onto the device's gateway or the endpoint host (or feed it to wireproxy for a no-root, userspace tunnel) and every packet it sends now sources from its own /128. The backend 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. Point the FHIR Endpoint.address (or Device.url) at the /128's name and the directory entry is now cross-checkable against the address itself: the self-verifying discovery ONC FAST and the NDH IG describe as missing today.

i

The whisper CLI ships create --register, verify --trustless, policy, logs, and kill --revoke. A dedicated --endpoint / --udi flag is on the roadmap, not shipped. Provision devices and endpoints today via the control-plane call above, which is live. When the flag lands it will be a thin wrapper over exactly this call.

DANE-pin the same UDAP endpoint cert, publicly

This is the highest-leverage move for anyone already speaking UDAP, and the strongest claim on this page. UDAP already asserts the binding you care about (this base URL is served by the holder of this certificate), but it asserts it only inside your community: the proof rests on a private trust anchor, and a relying party who never joined your community cannot check it.

Because the identity's DANE-EE TLSA 3 1 1 record pins the endpoint's leaf key, and the endpoint presents its UDAP server certificate on the /128, the very same base-URL↔cert binding UDAP asserts privately is now published in public, DNSSEC-signed DNS. Any relying party (inside your community or not, with no pre-provisioned anchor) validates it against the DNS chain to the IANA root:

# 1. the UDAP endpoint's base URL now resolves to a DNSSEC-signed, DANE-pinned /128
dig +dnssec TLSA _443._tcp.ep-c0def41d.fhir.<tenant>.agents.whisper.online +short
3 1 1 b653a4ef2c...c9f0d1  ; pins the SAME cert /.well-known/udap presents

# 2. pull the UDAP server cert and confirm the pin matches: no community anchor needed
openssl s_client -connect [2a04:2a01:f8e7:ca11:c0de:f41d:9a3d:71b2]:443 </dev/null 2>/dev/null \
  | openssl x509 -pubkey -noout | openssl pkey -pubin -outform DER | openssl dgst -sha256
# -> matches the TLSA 3 1 1 digest above == the base-URL↔cert binding, verified in public DNS

It is a second, orthogonal proof that complements, never replaces, your UDAP cert chain: the community anchor still governs who may register and exchange; DANE adds a publicly verifiable, DNS-rooted attestation of the exact SAN/base-URL binding UDAP defines, closing the base-URL↔cert-spoofing gap for parties outside the community, and it revokes at DNS-TTL (drop the TLSA and the endpoint stops verifying at the network layer immediately, publicly) rather than waiting on a community CRL/OCSP. For the record format, see DANE & TLSA; for keying a per-endpoint leaf, Per-agent CA.

A legacy HL7v2 or DICOM device, verifiable for the first time

The hardest devices in a hospital are the ones that will never speak modern crypto: an HL7v2 feed, a DICOM node whose AE-Title→IP:port mapping is "set at install by installation personnel," unauthenticated and not globally unique (internet scans find thousands of open DICOM servers accepting connections without AE-Title validation, exposing well over a billion images with under 1% on TLS). These devices can't hold their own key or take an agent, but the gateway in front of them can.

Provision one /128 per legacy device on that gateway (the serial separator gives each its own address), and the device it fronts now has, for the first time, a verifiable network identity: an AAAA, a forward-confirmed PTR, a DANE pin, and an RDAP record. A DICOM AE-Title→IP mapping that was manual and unauthenticated becomes DNSSEC/DANE-checkable; an HL7v2 interface behind a converged VLAN gets a name a peer can prove and an owner can revoke, without re-flashing a 15-year-old machine or bricking the clinical workflow.

Honest scope. This gives the legacy device a verifiable network identity and a governed egress path. It does not authenticate the clinical protocol itself. Two same-segment nodes trading an unauthenticated DICOM C-STORE or an injected HL7v2 message is a segmentation and protocol-auth problem, and stays one; Whisper anchors identity and reachability at the IP/DNS boundary, complementing microsegmentation and protocol-level auth, never standing in for them.

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 + identifier again (same tenant) the same /128 (a re-derivation, not a new allocation)
the same key with a different identifier (same tenant) 409: the reused identity is never silently re-pinned to a mismatched address
a non-string device_id (or serial) 400 with a helpful detail, never an opaque 500
device_id without identity_public_key 400: an endpoint derives its address from its own key

Verify: keyless, no account

The identity half is public on purpose: anyone (a QHIN allow-listing a peer endpoint, an auditor, a suspicious relying party) can prove an endpoint'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 endpoint, the name resolves back
dig -x 2a04:2a01:f8e7:ca11:c0de:f41d:9a3d:71b2 +short
ep-c0def41d.fhir.<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:f8e7:ca11:c0de:f41d:9a3d:71b2 | 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:f8e7:ca11:c0de:f41d:9a3d:71b2 | 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 ep-c0def41d.fhir.<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, precisely the relying party UDAP's private anchor can't serve. The full keyless walk lives in Verify an agent.

See who checked your endpoint: a recon tripwire

An identity you can prove is also an identity you can watch. Because every endpoint's name resolves through Whisper's own authoritative DNS and RDAP, the owner can ask who looked: op:'lookups' returns the PTR/AAAA/TLSA resolutions and RDAP accesses against a device's identity. That is an early-warning tripwire the community directory never gave you: someone enumerating your endpoints, or verifying a device before they reach for it, shows up before the connection lands, not in a post-mortem after exfil.

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:{agent:\"2a04:2a01:f8e7:ca11:c0de:f41d:9a3d:71b2\"}})"}' | jq .
# -> who resolved / RDAP-queried this endpoint's identity, and when

Its outbound companion is op:'logs' (the endpoint's own DNS and connection activity), the audit trail HIPAA §164.312(b) asks for. Non-repudiable, keyed to a forge-proof address rather than a spoofable last IP.

Govern what a device may reach: egress governance

The same address that proves a device is also the handle you govern it by. A graph-first resolver and source-bound egress enforce default-deny per device: a control-plane way to segment the machine that can't take a NAC agent, at Layer 3, by name:

# default-deny; allow only the clinical systems this device must reach
whisper policy set --agent 2a04:2a01:f8e7:ca11:c0de:f41d:9a3d:71b2 \
  --default deny --allow fhir.example-hdo.org,pacs.example-hdo.org

# per-device firewall by host / cidr / port; a spend + traffic cap with a kill-switch
CALL whisper.agents({op:'firewall', args:{agent:'2a04:2a01:f8e7:ca11:c0de:f41d:9a3d:71b2',
    allow:['pacs.example-hdo.org:11112'], deny:['0.0.0.0/0']}})
CALL whisper.agents({op:'budget', args:{agent:'2a04:2a01:f8e7:ca11:c0de:f41d:9a3d:71b2', max_mb_per_day:200}})

op:'policy', op:'firewall', and op:'budget' are shipped: allow/deny by category, geography, name, subdomain, host, CIDR, or port, and cap a device's traffic, so a compromised monitor that starts beaconing to C2 is choked at the egress before it exfiltrates, and one op:'revoke' (below) cuts it off worldwide. This is the network-segmentation control the HIPAA Security Rule NPRM and the HHS CPGs put front and center, delivered for devices that can't host an agent. Full surface in Egress governance.

Revoke: worldwide, in one call

A compromised, decommissioned, or resold device 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. That's the cross-organization kill-switch UDAP's in-community CRL/OCSP can't give you:

CALL whisper.agents({op:'revoke', args:{agent:'2a04:2a01:f8e7:ca11:c0de:f41d:9a3d:71b2'}})

# prove it (zero Whisper software): the same stock tools that proved it existed:
dig -x 2a04:2a01:f8e7:ca11:c0de:f41d:9a3d:71b2 +short           # -> nothing
curl -s https://whisper.online/verify-identity/2a04:2a01:f8e7:ca11:c0de:f41d:9a3d:71b2
# -> {"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. Contrast a credential burned at organization A but still valid against organization B, or a CRL you hope every relying party fetched. This is the substance behind FDA §524B(b)(1) postmarket containment: demonstrate you can revoke a single unit's identity in one call.

Nothing issued in the dark: the transparency log

Every identity mint and every revoke lands in a public, append-only RFC 6962 tlog-tiles Merkle log, with Ed25519-signed C2SP signed-note checkpoints, each root anchored to Bitcoin via OpenTimestamps. For a regulated device fleet that is an auditable, non-repudiable issuance-and-revocation trail. It's evidence you can hand an auditor for FDA §524B postmarket monitoring or a HIPAA asset-inventory review, cross-checkable without trusting Whisper's database:

curl -s https://whisper.online/checkpoint            # signed Merkle root + tree size
curl -s https://whisper.online/ip/2a04:2a01:f8e7:ca11:c0de:f41d:9a3d:71b2/transparency | jq .
# -> this endpoint's ordered lifecycle: mint, DANE pin, revoke, each a log leaf

Honest status. The log is tamper-evident, Ed25519-signed, and Bitcoin-anchored today, but it is not yet independently witnessed (ns1/ns2 co-signing is availability, not third-party independence). It already speaks the C2SP tlog-witness protocol, so an external witness can co-sign; until one does, treat it as strong tamper-evidence, not third-party attestation. It is also GDPR-compatible: leaves are salted opaque commitments, and op:'erase' destroys the salt so a leaf's meaning is unrecoverable while the proofs stay valid. More in Transparency log and OpenTimestamps.

Attribution: name whoever already scraped you

Identity stops the next forgery. To name whoever already scraped an endpoint or a fleet, across rotating clouds and residential proxies, and critically across organizations (41% of 2024 healthcare breaches originated with a third-party vendor), 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 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(\"203.0.113.45\")"}' | jq .
# operator fingerprinted across clouds; residential swarm collapsed by JA4: one operator, not a last IP

The read-only Cypher surface (identify, origins, walk, variants, history) runs over the same POST https://graph.whisper.security/api/query with your key, each returning a reproducible, replayable JSON evidence chain your SOC, your privacy office, and OCR can replay: the cross-organization vantage inventory tools structurally can't reach, since theirs stops at one hospital's edge. There is no whisper identify CLI subcommand. This is the API call, and it is live. Full verbs and shapes in Graph & cognition.

Lifecycle, end to end

The whole thing reads as one arc, and every stage is a single call against the address:

time → Endpoint / device key born on-device Endpoint.id / UDI Provision /128 · DANE · PTR · RDAP · egress op:'connect' In-life · govern & watch policy · firewall · budget · lookups · logs op:'policy' … op:'lookups' Incident / recall cut off worldwide, DNS-TTL op:'revoke' Decommission / resale retire → re-register to owner revoke (+ erase · GDPR) public Merkle transparency log every mint & revoke · Ed25519-signed · Bitcoin-anchored
One identity, tracked from the on-device key to decommission: each stage a plain whisper.agents call. In life, op:'policy'/op:'firewall'/op:'budget' govern what it may reach while op:'lookups'/op:'logs' show who checked it and what it reached; every mint and revoke is written to the public log.

A board swap or a re-key mints a new /128 and revokes the old one; a resale or a change of custodian is one revoke and a re-register to the new owner; a decommission is one revoke and, if you must erase, one op:'erase'. Compromise one device and you've compromised that device, not the fleet: the "a stolen secret is the whole fleet" failure mode is structurally removed. Nothing is issued, and nothing is torn down, in the dark.

Where this fits, and where it doesn't

Whisper anchors identity at the device/endpoint ↔ network IP boundary: the endpoint your backend authorizes and your directory publishes. 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 transport edge.

For mapping these identities to FDA §524B(b)(1)/(2) authentication and postmarket containment, the HIPAA Security Rule's asset-inventory / network-map / segmentation and §164.312(a)/(b)/(d) controls, EU MDR Annex I §17.4, and IEC 62443 FR1 (IAC), see FDA 524B · HIPAA · MDR. The Splunk connector is shipped; a Microsoft Sentinel connector, OpenCTI, and STIX 2.1 / TAXII export are on the roadmap and labelled as such there. No specific device maker, hospital, health system, or clearinghouse is named, endorsed, or implicated as a breach victim anywhere in these docs; the abuse patterns cited are the public, cross-industry ones.

Next