# Telecom

**A reachable NRF shouldn't be able to impersonate any network function in the core.**

Inside the 5G service-based architecture, one function authenticates another with mutual TLS at the handshake. But the identity it proves is a certificate signed by an *operator-private* CA, verifiable only to that operator, and the authorization step above it is *optional by spec*. Whisper closes the gap with one primitive: the network function's address *is* its identity, bound to the `nfInstanceId` the NF already carries in its certificate SAN, DNSSEC/DANE-anchored, and publicly verifiable across operators. This page is the telecom front door to the Whisper docs. The full technical library (DNSSEC, DANE, RDAP, the control-plane API) sits one click down the sidebar, shared verbatim with [whisper.online/docs](https://whisper.online/docs).

## The problem: reachability ≈ authorization

The 5G core is a flat, all-IP mesh of HTTP/2 + JSON microservices: AMF, SMF, UPF, PCF, UDM, AUSF, each registering a `NFProfile` with the **NRF** and discovering peers through it (3GPP TS 29.510). Mutual TLS on the service-based interface is mandatory; OAuth2 token-based authorization between an NF and the NRF is **not**. [TS 33.501 §13.3.1.3](https://www.etsi.org/deliver/etsi_ts/133500_133599/133501/) makes it optional, and GSMA's 5G Interconnect Security group flagged this as a structural weakness. The consequence is blunt: **reachability becomes authorization.** Any NF that can reach the NRF can pull any other NF's profile and *impersonate* it, or deregister a live NF for a clean, stealthy denial of service. The mesh inherits the entire web-and-API threat model: broken object-level authorization ([OWASP BOLA](https://owasp.org/API-Security/editions/2023/en/0xa1-broken-object-level-authorization/)), over-scoped tokens, exposed SBIs, all one microservice hop from the subscriber plane.

And the identity that *does* exist doesn't travel. Every NF certificate chains to a private, per-operator root, so no roaming partner, IPX carrier, regulator, or other operator can independently confirm "this really is operator X's AMF." Trust is asserted, never provable. The modern stack is weakest at the **N32** roaming interface between two SEPPs, mediated by semi-trusted IPX hubs, and at the legacy **SS7 / Diameter / GTP** interconnect, which trusts by default and lives on indefinitely for backward compatibility. That unverifiable identity is exactly the seam an attacker works.

```
   One reachable NRF → every NF: every egress is disposable

  Any SBI client        NRF                       NFProfiles: the whole core
  reach ≈ authz  ──in-mesh──▶ 5G discovery   ─┈▶  ▢ ▢ ▢ ▢ ▢ ▢ ▢ ▢ ▢
  OAuth2 optional §13   TS 29.510                 ▢ ▢ ▢ ▢ ▢ ▢ ▢ ▢ ▢
                        hands out every NFProfile ┌───────────────────────────────────┐
                        claim ✓ · machine ✗       │ impersonate · deregister (DoS) ·  │
                                                  │ N32 spoof · IRSF                  │
                                                  └───────────────────────────────────┘
  …reached in through disposable egress:
  [ IPX hub ] [ cloud VM ] [ grey route ] [ residential swarm ] ─▶ SOC logs a meaningless last IP
```

The whole kill chain leans on one spec footnote: OAuth2 authorization at the NRF is *optional* (TS 33.501 §13), so reachability becomes authorization. The egress is disposable too, so the *last IP* the SOC records was never the attacker.

The bill is not theoretical. The CFCA puts global telecom fraud at **$38.95B in 2023**, roughly 2.5% of revenue. **$6.23B a year of that is International Revenue Share Fraud**, a category that rides entirely on interconnect trust. The roaming fix built to harden this, the SEPP, is barely deployed: industry analysis reports **~70% of operators lack the cloud-native capability** a SEPP needs. Independent pentesting has found the legacy planes wide open: one vendor assessment reported **every one of 28 tested operator networks** vulnerable to GTP-based impersonation, fraud, or denial of service (Positive Technologies, ~2020, vendor pentest, dated). Detection will always trail a credential or a signaling peer that is genuinely trusted. The strictly-stronger move is to change what the counterparty trusts.

## The cure: the address is the NF

> **Shipped & live.** Deriving an NF `/128` from the network function's own SBA key + the `nfInstanceId` it already carries is in production today. Provision one with the control-plane call below and verify it from the DNSSEC root, across operators, with tools already on your machine.

Whisper gives each network function (AMF, SMF, UPF, PCF, a SEPP, an O-RAN component) a routable IPv6 `/128` out of `2a04:2a01::/32` (announced by **AS219419**), derived *deterministically* from the NF's **public key**: its `SubjectPublicKeyInfo`, the public half of the SBA certificate the NF already presents on mutual TLS, with the **nfInstanceId** as the domain separator. That UUID is not incidental. [TS 33.310 §6.1.3c](https://www.etsi.org/deliver/etsi_ts/133300_133399/133310/) mandates the SBA certificate carry a `subjectAltName` URI-ID of `urn:uuid:<nfInstanceId>`, so the key ↔ instance-id ↔ endpoint binding *already exists*, just sealed inside the operator's private CA. The private key never leaves the NF; only its public SPKI is an input. The result is [DNSSEC](/docs/dnssec)-anchored, [DANE-EE `3 1 1`](/docs/dane) pinned to that same certificate, and [RDAP](/docs/rdap)-registered: re-derivable and verifiable by anyone with `dig`.

```
NF key + nfInstanceId       ──public SPKI + nfInstanceId──▶   /128                   ──DNSSEC · DANE 3 1 1 · RDAP──▶   any operator verifies it
SBA cert · urn:uuid SAN                                       2a04:2a01:5e0::a3f                                     whisper verify --trustless
ECDSA · CMPv2-enrolled                                        → NFProfile.ipv6Addresses                              (no cross-cert · no NRF access)
(private key stays on the NF)                                                                                       └─▶ op:'revoke' → gone worldwide at DNS-TTL
```

The `nfInstanceId` is already a URI-ID in the NF's certificate SAN (TS 33.310), an identity trapped in a private, per-operator CA. Whisper binds the same UUID, from the NF's own key, to a routable, publicly verifiable `/128` that drops straight into `NFProfile.ipv6Addresses`, and gives it the cross-operator off-switch the private root never had.

Because the derivation is **tenant-bound**, the same NF key under two operators yields two unrelated `/128`s: an outsider cannot link a function across networks, which sits naturally alongside the topology hiding a SEPP already performs. Because the domain separator is the `nfInstanceId`, **the instance-id alone yields nothing**: it flows through every discovery response and is not a secret, yet 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 operational whereabouts.

What becomes true the moment an NF holds one:

- **"Reachable ⇒ impersonable" becomes false.** You cannot present an NF identity whose key you don't hold; every forgery is a DNSSEC/DANE inconsistency any counterparty catches, even one that reached the NRF.
- **The private-CA blind spot closes at the boundary.** A roaming partner, an IPX peer, or a regulator resolves the `/128`, pulls the DANE pin, and confirms "this address is NF X", without cross-certifying your operator CA and without any NRF access.
- **The DNS-spoofing / rogue-NRF gap closes.** 3GPP mandates mTLS and OAuth2 but *not* DNSSEC/DANE on the SBA name layer; spoof the DNS under NF discovery and you redirect to a rogue NRF or a forged token-issuer URL. A DNSSEC-signed, DANE-pinned name→address→expected-cert binding is exactly what mTLS alone does not cover.
- **One `revoke` kills a compromised NF worldwide** at DNS-TTL speed: a cross-operator kill-switch that a per-operator CRL or OCSP responder can't provide, because those don't cross the operator boundary.

**Additive, never a replacement.** Whisper complements the controls 3GPP already mandates: mutual TLS on the SBI, OAuth2 authorization with the NRF as authorization server, the operator-private CA and CMPv2 enrolment, SEPP N32-c/N32-f and PRINS topology hiding, O-RAN WG11's mTLS + CMPv2. It is the publicly verifiable, DNSSEC/DANE-anchored layer *on top*, anchoring the trust boundaries where independent verification actually matters: NF discovery and the DNS beneath it, the N32 roaming border, NEF/CAMARA exposure, and management, all at the IP, DNS, and transport layer. You can even [DANE-pin](/docs/dane) your existing SBA endpoint's certificate to DNSSEC and cut single-CA mis-issuance risk out-of-band. Whisper never reaches into the mTLS session on the SBI itself, the 5G-AKA / SUCI subscriber plane, or the O-RAN fronthaul; it keeps the `nfInstanceId`'s existing cert binding and adds the two things a private root lacks: public cross-operator verifiability and DNS-TTL revocation, with no NRF OpenAPI change and no re-key.

Nothing is issued in the dark: every mint and every revoke lands in a public, append-only [Merkle transparency log](/docs/transparency), Ed25519-signed and anchored to Bitcoin via OpenTimestamps, that you, a peer operator, and a regulator can audit. (Honest status: tamper-evident and Bitcoin-anchored today; independent third-party witnessing is the next step, and the log already speaks the witness protocol.)

## Provision an NF identity

Provisioning is one control-plane call over the public API: `POST https://graph.whisper.security/api/query` with your `X-API-Key`. Hand it the NF's base64 SPKI and its `nfInstanceId`; it returns the deterministic `/128` and a WireGuard config for source-bound egress:

```
CALL whisper.agents({op:'connect', args:{
  tier:'wireguard',
  identity_public_key:'<base64 SPKI of the NF's SBA key>',
  device_id:'3f2504e0-4f89-11d3-9a0c-0305e82c3301'   // the nfInstanceId (urn:uuid in the cert SAN)
}}) YIELD op, ok, status, result, error
RETURN op, ok, status, result, error
```

Send it with your key. The heredoc keeps the single-quoted Cypher literals intact, so this runs as-is:

```sh
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:'3f2504e0-4f89-11d3-9a0c-0305e82c3301'}}) YIELD op, ok, status, result, error RETURN op, ok, status, result, error"}
JSON
```

```json
// response
{ "op": "connect", "ok": true, "status": "created",
  "result": {
    "address": "2a04:2a01:5e0::a3f",
    "fqdn":    "nf-3f2504e0.amf.<tenant>.agents.whisper.online",
    "wireguard": { /* peer, keys, allowed-ips */ }
  } }
```

The call is **idempotent and liberal in what it accepts, strict in what it returns**: re-running with the *same* key and `nfInstanceId` returns the *same* `/128`; a *different* instance-id for a key already registered 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, not an opaque 500. That's the same Postel discipline the NRF itself shows when it answers bad JSON with a `ProblemDetails` object instead of a stack trace. The `device_id` argument is generic: pass the `nfInstanceId`, the OAuth2 `client_id` (which *is* the `nfInstanceId`), or a SEPP's identity, whatever native identifier the function carries.

> The returned `/128` drops straight into the NF's `NFProfile.ipv6Addresses` at the NRF: no OpenAPI change, no re-registration, no new key. A dedicated `--nf-instance-id` CLI flag is on the roadmap; today, NF provisioning is the control-plane call 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](/docs/cli).

## Verify it yourself, no account needed

Every NF identity is checkable with no key and no login, from the internet's own records. That's the whole point at a trust boundary, where the party checking is a *different* operator. The `whisper` CLI does the full walk in one call:

```
whisper verify --trustless nf-3f2504e0.amf.<tenant>.agents.whisper.online

✓ DNSSEC chain valid to the IANA root
✓ DANE-EE (TLSA 3 1 1) leaf matches the NF's SBA certificate
✓ RDAP: registered under AS219419 · 2a04:2a01::/32
identity: VERIFIED, and our own API was never trusted
```

Or reach for the raw records directly: the same answer, from stock tools:

```sh
# the public verify endpoint: evidence chain in JSON
curl -s https://whisper.online/verify-identity/2a04:2a01:5e0::a3f | jq
# { "is_whisper_agent": true, "dane_ok": true, "jws_ok": true, "evidence": { … } }

# the address is the NF: forward-confirmed reverse DNS names it
dig -x 2a04:2a01:5e0::a3f +short
# nf-3f2504e0.amf.<tenant>.agents.whisper.online.

# the registry object: who holds the address, and under which allocation
curl -s https://whisper.online/ip/2a04:2a01:5e0::a3f | jq
```

None of these calls Whisper as an authority. `--trustless` re-derives the proof against the public DNSSEC root, exactly as any resolver could. A home operator can verify a visited network's peer NF or SEPP against a public anchor instead of trusting the SEPP's assertion or an IPX hub in between. See [Verify an agent](/docs/verify) for the full keyless check and [DANE & TLSA](/docs/dane) for the pin, byte for byte.

## Revoke worldwide and govern in between

A compromised NF, a decommissioned function, a rotated key, a de-peered interconnect partner: one call tears down the `/128`, its PTR, and its DANE pin everywhere at DNS-TTL speed:

```
CALL whisper.agents({op:'revoke', args:{agent:'2a04:2a01:5e0::a3f'}})

# after the TTL: dig -x returns nothing, verify returns false
whisper kill --revoke 2a04:2a01:5e0::a3f
```

This is a cross-operator kill-switch that propagates at cache-TTL: no bilateral PKI exchange, no per-operator CRL you hope every peer fetched. **Honest boundary:** this revokes the *identity, its route, and its egress authorization* faster than CRL/OCSP; it does *not* revoke the operator's SBA TLS certificate. That stays your operator CA's job. Sell it as an additional, faster kill-switch, not a replacement for CMPv2 revocation. Revocation is the endpoint; the same control plane also governs what a *live* NF may reach in between. Egress is source-bound to the NF's `/128`, so policy is enforced by name and by address:

```
# default-deny: this NF may reach ONLY its NRF and its peer SEPP
whisper policy set --default deny --allow nrf.5gc.example-mno.net,sepp.5gc.example-mno.net

# per-NF firewall (allow/deny by host, cidr or port) and a traffic budget + kill-switch
CALL whisper.agents({op:'firewall', args:{agent:'2a04:2a01:5e0::a3f', deny:['0.0.0.0/0'], allow:['nrf.5gc.example-mno.net:443']}})
CALL whisper.agents({op:'budget',   args:{agent:'2a04:2a01:5e0::a3f', max_mb_per_day:500}})
```

Per-NF `/128` plus egress governance is a network-layer micro-perimeter against lateral movement: the isolate-workloads posture NSA/CISA's ESF 5G Cloud guidance asks for, and the Identity and Visibility pillars of the CISA Zero-Trust Maturity Model, expressed as one call to provision and one to revoke. Because each record and telemetry stream can be bound to, and [signed under](/docs/sign-outputs), the NF's forge-proof `/128`, a peer operator, an interconnect partner, or your own settlement can trust the numbers came from the real function, not a spoofed feed. See [Egress governance](/docs/egress-governance) for the full policy surface.

## Attribution: name whoever already reached you

Identity stops the next forgery; the graph names the operator behind the sessions already in your logs: attribution that survives IP rotation because it fingerprints the operator and the tooling, not the ephemeral egress IP behind an IPX hub, a cloud VM, or a residential proxy. Run it as read-only Cypher over the same public API with your key (there is no CLI subcommand for this; it is the graph API directly):

```sh
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.x.x.x\")"}'
# operator fingerprinted across IPX / cloud / residential; egress swarm collapsed by JA4
```

The read-only verbs (`identify`, `origins`, `walk`, `variants`, `history`) each return a reproducible, replayable JSON evidence chain your core-NF SOC, your PSIRT, and a regulator can replay. Cryptographic attribution is exactly what the **NIS2** incident-reporting clock needs (Art. 23: early warning within 24h, notification within 72h, final report within a month), so you can name who and where instead of shipping a meaningless last IP. More in [Graph & cognition](/docs/graph-api).

## Lookups: see who's enumerating your core

An identity you can prove is also an identity you can *watch*. Because every NF's name resolves through Whisper's own authoritative DNS and RDAP, the owner can ask who looked: a reconnaissance tripwire the private, out-of-band NRF registry never gave you. `op:lookups` returns who resolved or RDAP-queried an NF's identity, so you see a roaming partner or a would-be peer *enumerating* your core before an N32 message lands, not in the post-mortem afterward:

```
CALL whisper.agents({op:'lookups', args:{agent:'2a04:2a01:5e0::a3f', window:'24h'}})

# the same reverse-observability view, keyless, per address
curl -s https://whisper.online/ip/2a04:2a01:5e0::a3f/lookups | jq
# → who resolved this NF's PTR/AAAA/TLSA and hit its RDAP object, and when
```

Paired with `op:logs` (the NF's own outbound activity) and `/ip/<addr>/transparency` (its ordered lifecycle in the Merkle log), you have both halves of the picture: what an NF reaches out to, and who is reaching in to look at it.

## What ships today, and what's on the roadmap

We label these honestly so you can plan against them.

| Shipped & live | On the roadmap |
|---|---|
| NF `/128` from the NF's SBA key + `nfInstanceId`: DNSSEC + DANE-EE + RDAP | A dedicated `--nf-instance-id` CLI flag (provision via the control-plane call today) |
| Control-plane provision, verify, revoke; egress governance (`policy`/`firewall`/`budget`); `op:lookups`; the Merkle transparency log; the attribution graph over the public API | **STIX 2.1 over TAXII** export |
| The **Splunk**, **Microsoft Sentinel** and **OpenCTI** connectors (signed, replayable JSON → CEF / ECS fields) | telecom-ISAC machine-readable JSON export |

The integration guides below describe **proposed** integrations at the SBI, roaming, and IP boundary, designed to complement the stack you already run, not endorsed by 3GPP, GSMA, or any vendor, and never named against a specific operator as a breach victim. Two honest boundaries worth stating plainly: this is *not* a GSMA NESAS / SCAS certification control and *not* an EU CRA conformity route. It is a defense-in-depth differentiator and a PSIRT attribution tool. It does nothing for FCC rip-and-replace, which is a supply-chain-provenance problem of a different class. Nation-state router and edge implants live below the identity layer; we cite those campaigns only as class-level proof that cross-operator attribution and fast eviction remain unsolved, never as something an identity layer alone would have stopped.

## The five Telecom guides

The telecom story, in depth: each page is self-contained and copy-paste runnable.

- **[NF identity](/docs/nf-identity).** Derive a routable `/128` from the `nfInstanceId` a network function already carries in its cert SAN. Deterministic, tenant-bound, DNSSEC + DANE-EE pinned (the NF-identity spine).
- **[NF-impersonation cure](/docs/nf-impersonation-cure).** Why a reachable NRF and OAuth2-optional-by-spec let any NF impersonate any other, and how a forge-proof address ends it (the reachability≈authorization root cause, cured at the identity layer).
- **[NRF · SEPP · CAMARA · O-RAN](/docs/telecom-integrations).** Proposed integrations at the SBI/IP boundary: the `/128` into `NFProfile.ipv6Addresses`, DANE-pinned peer identity at N32/SEPP, CAMARA / Open Gateway, O-RAN ZTA Identity. Complements, never replaces.
- **[NESAS · NIS2 · 5G Toolbox](/docs/telecom-compliance).** Map identity and attribution evidence to NIS2 Art. 21/23, the EU 5G Toolbox (TM02), GSMA NESAS/FS.36, and NSA/CISA ESF 5G Cloud, as a network primitive, not a binder.
- **[Verify · attribute · govern](/docs/telecom-recipes).** Runnable recipes: DANE-pin a peer SEPP at the N32 border, default-deny a compromised NF's egress, back-trace a rotating IPX egress on the graph.

## The full technical library

Telecom rides on the same address-is-identity platform as every other agent on the network, so the whole shared library applies here unchanged, and every page has a clean Markdown twin at the same path + `.md`. Start with these; the rest is in the sidebar.

- **[Quickstart](/docs/quickstart).** Install, register your first identity, connect it, confirm it: one terminal, start to finish.
- **[Verify an agent](/docs/verify).** The full keyless identity check: every proof you run with `dig`, `curl`, and `openssl`.
- **[DANE & TLSA](/docs/dane).** The `3 1 1` pin that makes an address forge-proof, byte for byte, no CA in the path.
- **[Control plane](/docs/control-plane).** The full `whisper.agents` API (provision, connect, policy, logs, revoke) over the public endpoint.

---

← [For operators](https://telecom.whisper.online/for-operators) · [NF identity →](/docs/nf-identity)
