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:
- Deterministic & idempotent: the same key +
nfInstanceIdalways yields the same/128. Re-provisioning a redeployed pod for the same NF instance returns the same address; there is no registry to keep in sync with the NRF. - Tenant-bound & fleet-unlinkable: the derivation folds in your operator tenant, so the same NF instance under two operators yields two unrelated
/128s. No one can link an instance across the PLMN boundary by suffix, and there is no enumeration oracle. - Forge-proof: the
/128is DANE-EE3 1 1-pinned to that NF's own SBA certificate and has DNSSEC-signed reverse DNS. A rogue NF with a different key derives a different address and can't present the pinned key. - Revocable across operators: one control-plane call tears the
/128, its PTR, and its DANE pin down everywhere at DNS-TTL speed. That beats one CRL per operator that peers may never fetch.
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"]
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.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
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'"'"'}})"}'
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
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.
| Recipe | Complements | Does not touch / replace |
|---|---|---|
| 1 · Bind an NF identity | the urn:uuid:nfInstanceId cert (TS 33.310) + mandatory SBI mTLS + OAuth2 | the NRF API (no change), the operator CA (still issues the cert), the SBI handshake |
| 2 · Keyless NF verify | SBI mTLS across the PLMN / IPX boundary | the mandatory mTLS + OAuth2 at the handshake; issues no NF certs |
| 3 · DANE-pin the SBA endpoint | TS 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 graph | signaling firewalls (SS7 / Diameter / GTP) + SEPP / N32 | signaling / packet-core inspection; not a claim to evict a below-identity implant |
| 5 · Govern NF egress | 5G-core firewalls · NSA/CISA ESF micro-segmentation | inline GTP-U / SCTP inspection; adds no user-plane chokepoint |
| 6 · Lookups tripwire | NRF 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
- NF identity: the full derivation the
/128above comes from, SBA key +nfInstanceIdto address - DANE & TLSA: the
3 1 1pin every check here rests on, byte for byte - Verify an agent: the full keyless proof chain
whisper verify --trustlesswalks - NESAS · NIS2 · 5G Toolbox: where these recipes map into audit and incident-reporting evidence