Whisper · Docs
Telecom · Recipes

Verify · attribute · govern

Six copy-paste recipes give every 5G network function an identity it can prove, an operator you can name behind a rotating peer, and an egress you can govern to one call. Each one runs today against the keyless surface anyone can reach.

They share one primitive: a routable IPv6 /128 that an NF derives from the SBA mTLS key it already holds. That's the same key whose certificate SAN already carries urn:uuid:<nfInstanceId> (3GPP TS 33.310 §6.1.3c). It is DNSSEC-signed and DANE-pinned to that same certificate, so any operator, IPX or regulator can verify it and nobody can forge it, without your private CA in the path. Everything below is built from shipped parts: the NF /128, keyless verify, the attribution graph, egress governance, 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 NF /128 derivation (public key + device_id = the nfInstanceId), the keyless verify / RDAP surface, the attribution graph over the public API, egress governance (policy/firewall/budget), lookups, and one-call revoke are live. Two caveats these recipes are written around: there is no first-class --nf-instance CLI flag yet, so NF provisioning is shown via the control-plane API (which is live); and the STIX · TAXII export connector named at the end is roadmap; the Splunk, Microsoft Sentinel and OpenCTI connectors ship today. Whisper anchors the DNS / IP / transport boundary: it is a second, independent DNS-anchored layer beside your mandatory SBI mTLS + OAuth2, never a replacement for them, the operator PKI, the NRF, or the SS7/Diameter signaling plane. Each recipe names exactly where it stops.

The shared primitive: the address is the NF

Every 5G NF (AMF, SMF, UPF, PCF, UDM, AUSF, NSSF, or a SEPP) is an HTTP/2 + JSON microservice on the SBI that registers a NFProfile with the NRF (TS 29.510). That profile already carries the NF's nfInstanceId (an RFC 4122 UUID), its nfType, and at least one of fqdn / ipv4Addresses / ipv6Addresses. Mutual TLS is mandatory on the SBI, and the certificate is the identity anchor. But it's signed only by the operator-private CA, so no roaming partner, IPX or regulator can independently check it. Whisper takes only the public SubjectPublicKeyInfo (SPKI) of that same SBA key and, with the nfInstanceId as the domain separator, deterministically derives a /128 under 2a04:2a01::/32 (AS219419). The private key never leaves the NF.

The derivation has four properties that make it useful as an identity rather than just an address:

Because the domain separator is the nfInstanceId, the UUID alone yields nothing: you cannot go nfInstanceId → /128 without the key, there is no enumerable directory, and RDAP and reverse-DNS return the registry object, never the NF's internal whereabouts. The nfInstanceId is the public fingerprint that flows through every NRF registration; the /128 is its cryptographic counterpart. Once an NF holds one, every check in the six recipes below is keyless: no account, no API key, just DNS and TLS any counterparty already has.

Recipe 1 · Bind an NF to the nfInstanceId it already carries

Shipped & live. Deriving an NF /128 from the SBA key it already holds, keyed by its nfInstanceId, is in production today. Provision one with the control-plane call below, then drop the address straight into NFProfile.ipv6Addresses. No NRF API change, no re-keying, no new CA.

Pass the NF's base64 SPKI as identity_public_key and its nfInstanceId as device_id. That UUID is the exact one already in the cert SAN (urn:uuid:<nfInstanceId>, TS 33.310). Re-running with the same key + UUID returns the same /128:

# Bind an NF: device_id = its nfInstanceId (the urn:uuid already in its cert SAN).
# Idempotent: same key + nfInstanceId returns the SAME /128, no NRF registry to sync.
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 NF SBA key>'"'"', device_id:'"'"'3f2504e0-4f89-11d3-9a0c-0305e82c3301'"'"'}}) YIELD op, ok, status, result, error RETURN op, ok, status, result, error"}' | jq .
# response
{ "op": "connect", "ok": true, "status": "created",
  "result": {
    "address": "2a04:2a01:5e0::a3f",
    "fqdn":    "nf-amf-3f2504e0.sbi.example-plmn.whisper.online",
    "wireguard": { /* peer, keys, allowed-ips: source-bind the NF's egress to its /128 */ }
  } }

Confirm the address and its forward-confirmed name, then place the /128 into the NFProfile you PUT to the NRF. It lives in the field that was always there for it:

# The address is the NF. Forward-confirmed reverse DNS names it:
dig +short -x 2a04:2a01:5e0::a3f
nf-amf-3f2504e0.sbi.example-plmn.whisper.online.

# Drop it into the NFProfile you register with the NRF (TS 29.510). No API change:
#   "nfInstanceId":  "3f2504e0-4f89-11d3-9a0c-0305e82c3301"
#   "ipv6Addresses": ["2a04:2a01:5e0::a3f"]
the same UUID the NF already carries in its cert SAN, now anchored in the public DNSSEC root AMF · SBA mTLS key urn:uuid in cert SAN · TS 33.310 private key stays in the NF only public SPKI is an input public key + nfInstanceId /128 2a04:2a01:5e0::a3f → NFProfile.ipv6Addresses DNSSEC + DANE-EE 3 1 1 A name any operator verifies whisper verify --trustless no operator private CA in the path op:revoke → gone across operators at DNS-TTL
The NF certificate already carries urn:uuid:<nfInstanceId> in its SAN (TS 33.310), a good key-bound identity trapped in an operator-private CA. Whisper binds the same UUID to a routable, publicly verifiable /128 and gives it a cross-operator off-switch. One leaf key per identity; never a shared root.
i

The call is liberal in what it accepts, strict in what it commits: the same NF key with a different nfInstanceId on your tenant is a clear 409, not a silent overwrite; a non-string device_id is a 400 that tells you exactly what was wrong, never an opaque 500. The server only ever derives a public address; it never sees or reconstructs the NF's private key. Nothing changes in the NRF, the SBI handshake, or your operator CA. This is a second identity on top of the one you already run.

Recipe 2 · Prove an NF's identity, keyless

Mutual TLS proves the NF at the SBI handshake: to a counterparty that already trusts your operator CA. Across the PLMN boundary, through an IPX, or to a regulator, no one can chain your private-CA cert to a public anchor. The /128 closes that: any party re-derives and checks the identity trustlessly against the IANA DNSSEC root, with no Whisper API and no operator CA trusted as an authority.

Boundary. This complements the mandatory SBI mTLS + OAuth2 (TS 33.501 §13); it does not replace them and does not issue NF certificates. It adds the publicly-verifiable check (the one a roaming partner, an IPX hub, or an auditor can run without bilateral cross-certification) at exactly the multi-party boundary the operator-private PKI can't cross.

The CLI walks the full proof chain in one line. It's the same check either side of a peering runs against the other:

# Trustless: re-derived against the IANA DNSSEC root; no operator CA trusted as an authority.
whisper verify --trustless nf-amf-3f2504e0.sbi.example-plmn.whisper.online

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 (the NF's own SBA cert)
ledger   pass   DNSSEC-root   transparency-log entry present, signature verifies
CRYPTOGRAPHICALLY PROVEN, trust anchor: DNSSEC root (IANA) + DANE-EE, operator CA NOT trusted

No CLI required. The same fact answers over one keyless HTTPS call, and again with nothing but dig, the tool already in every ops toolbox:

# The public verify endpoint. Evidence chain in JSON, no account:
curl -s https://whisper.online/verify-identity/2a04:2a01:5e0::a3f
{"is_whisper_agent":true,"dane_ok":true,"jws_ok":true,
 "evidence":{"address":"2a04:2a01:5e0::a3f",
   "ptr":"…","forward_aaaa":"2a04:2a01:5e0::a3f"}}

# Because the reverse is forward-confirmed (PTR ⇄ AAAA), dig alone proves the name:
dig +short -x 2a04:2a01:5e0::a3f
nf-amf-3f2504e0.sbi.example-plmn.whisper.online.

That is a mutual, forge-proof peer check at the layer the private PKI leaves open across operators: neither side depends on a token that could be replayed from another host, and neither has to trust a CA the other one chose.

Recipe 3 · DANE-pin your SBA endpoint to public DNSSEC

This is the least-contestable recipe on the page. 3GPP mandates mTLS and OAuth2, but not DNSSEC or DANE on the SBA name layer that NF and NRF discovery ride on. That layer is unsigned. Spoof DNS and you redirect a consumer NF to a rogue NRF, or forge the token-issuer URL, and mutual TLS never sees it, because the client was steered to the attacker's name before the handshake began. A DNSSEC-signed zone plus a DANE TLSA record pinning the same certificate your NRF already presents makes the name → address → expected-cert binding cryptographic and hijack-resistant.

Boundary. DANE pins the cert out of band; it does not revoke the operator TLS certificate (that stays the operator CA's job) and it does not replace mTLS. It is a second, independent DNS-anchored check that closes the DNS-spoofing / rogue-NRF / forged-issuer vector TS 33.501 leaves open, plus a faster kill-switch. It maps to EU 5G Toolbox TM02 (turn on optional security controls) and hardens the N32-c spoofing vector GSMA FS.36 names.

Publish the pin: the SHA-256 of the NRF endpoint certificate's SubjectPublicKeyInfo, as a DANE-EE 3 1 1 record in the DNSSEC-signed zone:

# The DNSSEC-signed TLSA pin for the NRF's SBI endpoint (selector 1 = SPKI, match 1 = SHA-256):
dig +short TLSA _443._tcp.nrf.sbi.example-plmn.whisper.online
3 1 1 b653a4ef…fcb82d1d

Now any consumer NF checks the NRF it was pointed at against that pin before it trusts a discovery answer or a token issuer. A rogue NRF answering on the name cannot present the pinned key, so the check fails and the redirect is caught:

# On the consumer NF, before trusting the NRF answer: does the live cert match the pin?
openssl s_client -connect nrf.sbi.example-plmn.whisper.online:443 </dev/null 2>/dev/null \
  | openssl x509 -pubkey -noout | openssl pkey -pubin -outform der \
  | openssl dgst -sha256        # must equal the TLSA pin above; a rogue NRF can't

# Or let the CLI do the whole DNSSEC + DANE walk for the NRF endpoint in one line:
whisper verify --trustless nrf.sbi.example-plmn.whisper.online
dane   pass   DNSSEC-root   served leaf SPKI-SHA256 == TLSA pin

Pin the SEPP the same way and the check extends to the N32 border: the home operator verifies a peer SEPP against a public anchor instead of trusting the SEPP's own assertion. It's the modern-stack analogue of the same move.

Recipe 4 · Back-trace the operator behind a suspicious peer

Identity stops the next impersonation; the graph names the operator behind a host already in your logs. That attribution survives rotation because it fingerprints the operator and the tooling, not the ephemeral egress IP. Rate-limit an IPX-hosted peer and a fresh IP appears; the egress hops across an IPX hub, clouds, and a residential-proxy swarm, so all your NF SOC ever logs is a meaningless last IP. The graph collapses it.

Boundary, stated plainly. This is an additive feed into the signaling firewalls (SS7 / Diameter / GTP) and the SEPP you already run; Whisper does not do signaling inspection or packet-core protection. And it is honest about its reach: attribution names the operator behind a rotating egress; it does not, by itself, evict a below-identity-layer implant or stolen management credential. Use it as the who/where accelerator for incident handling, not a claim to have stopped a nation-state-class campaign.

Pass the suspicious address to whisper.identify over the public graph API with your key. There is no whisper identify CLI verb; the read-only Cypher call below is the interface:

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(\"185.90.x.x\")"}' | jq .
  operator:  <fingerprinted> · seen across an IPX hub, AWS, GCP and Azure
  residential swarm collapsed by JA4: same tooling, 37 exit IPs → 1 operator
what your NF SOC sees: a rotating, meaningless “last IP” Rogue NF / peer presents a pulled NFProfile IPX hub · GRX 193.x.x.x AWS eu-central 3.68.x.x Azure westeu 20.61.x.x residential-proxy swarm 71.x · Comcast 82.x · KPN 99.x · Orange JA4-identical tooling infra genealogy JA4 fingerprint One operator ASN + hosting genealogy + JA4 / JA3 fingerprint evidence chain → your SIEM / SEPP what the graph sees: one operator
Attribution survives rotation because it tracks the infrastructure and the tooling, not the ephemeral egress IP. The read-only verbs (identify, origins, walk, variants, history) each return a reproducible, replayable JSON evidence chain your NF SOC, PSIRT, and a regulator can replay.

The finding accelerates the who/where forensics a NIS2 Art.23 report (24h / 72h / 1 month) demands, and it feeds straight into the signaling firewall and SEPP you already operate. It's enrichment, not a new console to babysit.

Recipe 5 · Govern NF egress: default-deny, allow the peers, cap, kill

An identity you can prove is also one you can govern. Because the NF's /128 resolves through Whisper's own graph-first resolver and its egress is source-bound to that address, you can enforce default-deny per NF: allow only the peers it legitimately talks to, cap its traffic, and cut it off in one call. This is anti-lateral-movement micro-segmentation at the network layer, the move NSA/CISA ESF 5G Cloud Parts II and III and the CISA ZTMM Identity + Visibility pillars ask for.

Boundary. This rides existing DNS / IPv6 and adds no inline packet chokepoint in the core. It is not a GTP-U / SCTP firewall (those incumbents keep their ✓). The DANE/verify plane is built to fail open: a Whisper outage never bricks an NF; checks degrade to your existing anchors. It complements the 5G-core firewalls; it does not sit in the user-plane path.

# Default-deny the NF, then allow only its legitimate SBI peers, by name or subdomain.
whisper policy set --default deny \
  --allow nrf.sbi.example-plmn.whisper.online,smf.sbi.example-plmn.whisper.online,sepp.sbi.example-plmn.whisper.online

# The same as a per-NF firewall over the control plane: allow/deny by host, cidr or port:
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:5e0::a3f'"'"', default:'"'"'deny'"'"', allow:['"'"'nrf.sbi.example-plmn.whisper.online'"'"','"'"'smf.sbi.example-plmn.whisper.online'"'"']}})"}'

# Cap the NF's egress and arm the kill-switch:
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:5e0::a3f'"'"', max_egress_gb:50, on_exceed:'"'"'kill'"'"'}})"}'
govern exactly what the NF may reach: allow the peers, block the mesh AMF 2a04:2a01:5e0::a3f default-deny egress NRF · discovery SMF · UPF peers SEPP · N32 border allow-list any other host · internet blocked op:budget · cap + kill-switch op:revoke · off across operators
Default-deny per NF, allow only the SBI peers it legitimately reaches, cap it with op:budget, and cut it off with op:revoke. That's a network-layer least-privilege perimeter around each /128, additive and availability-safe.

When an NF is compromised, or resold, decommissioned, or simply rotated out, one call tears down the /128, its PTR, and its DANE pin everywhere at once, bounded only by DNS TTL. No CRL to distribute, no bilateral PKI exchange:

# Kill an NF identity across operators. Every keyless check above starts returning
# "not a Whisper identity" within the DNS TTL, no coordination, no distribution list.
whisper kill --revoke 2a04:2a01:5e0::a3f
i

Nothing issued in the dark. Every provision and every revoke lands in a public, append-only RFC 6962 Merkle transparency log, Ed25519-signed and anchored to Bitcoin via OpenTimestamps: an auditable, non-repudiable issuance/revocation trail for a NIS2 Art.23 report or an SCAS review. Honest status: tamper-evident and Bitcoin-anchored today, but not yet independently witnessed (it already speaks the C2SP tlog-witness protocol, so an external witness can co-sign). And you can bind each SCAS / incident log line to the NF's forge-proof /128 with signed outputs, so a report attributes every logged action to the exact NF instance, not a claim.

Recipe 6 · See who queried your NF identity

Enumeration is Stage 1 of the impersonation kill chain: before anyone speaks as your AMF, they resolve and probe it. Because every NF identity resolves through Whisper's own authoritative DNS and RDAP, the owner sees exactly who looked: a reconnaissance tripwire the operator-private NRF never gave you. This is the reverse of op:logs (the NF's own outbound): op:lookups answers who checked this NF.

# The recon tripwire: who has been resolving / RDAP-querying this NF's identity?
# A spike in PTR/TLSA/RDAP lookups from an unexpected origin = someone enumerating
# before they impersonate. Early warning, not a post-mortem. No key required:
curl -s https://whisper.online/ip/2a04:2a01:5e0::a3f/lookups
{ "address":"2a04:2a01:5e0::a3f",
  "lookups":[ {"kind":"PTR","count":128,"first":"…","last":"…"},
              {"kind":"TLSA","count":91,"…":"…"},
              {"kind":"rdap","count":17,"…":"…"} ] }

# With your key, the same over the control plane: per NF, alongside op:logs:
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:5e0::a3f'"'"'}})"}' | jq .

Pair the tripwire with Recipe 4: an unexpected surge of lookups against your NRF's or a slice's NFs, then whisper.identify on the querying source, turns "someone is casing the core" from a hunch you find in an incident review into a named operator you can act on before the impersonation lands.

Where each recipe stops, and what's roadmap

Honest scoping, one row per recipe. Whisper anchors the DNS / IP / transport boundary; the SBI handshake, the operator PKI, the NRF, and the signaling plane stay exactly where they are.

RecipeComplementsDoes not touch / replace
1 · Bind an NF identitythe urn:uuid:nfInstanceId cert (TS 33.310) + mandatory SBI mTLS + OAuth2the NRF API (no change), the operator CA (still issues the cert), the SBI handshake
2 · Keyless NF verifySBI mTLS across the PLMN / IPX boundarythe mandatory mTLS + OAuth2 at the handshake; issues no NF certs
3 · DANE-pin the SBA endpointTS 33.501 mTLS · EU 5G Toolbox TM02 · GSMA FS.36 (N32-c)operator TLS-cert revocation (still the operator CA's job)
4 · Back-trace on the graphsignaling firewalls (SS7 / Diameter / GTP) + SEPP / N32signaling / packet-core inspection; not a claim to evict a below-identity implant
5 · Govern NF egress5G-core firewalls · NSA/CISA ESF micro-segmentationinline GTP-U / SCTP inspection; adds no user-plane chokepoint
6 · Lookups tripwireNRF access logs · SCAS TS 33.117 logging(a keyless read of your own identity's query record)

Roadmap, clearly labelled. Streaming this evidence into a SIEM ships today for Splunk, Microsoft Sentinel and OpenCTI (signed, replayable JSON → CEF / ECS fields). A STIX 2.1 over TAXII feed and a per-sector machine-readable export for sharing revocation and attribution evidence are proposed, not yet available. And the first-class typed --nf-instance CLI flag is roadmap. Provision NFs via the control-plane API shown above, which is live. Nothing on this list is required for the six recipes; they run on shipped primitives alone.

Next