# Content

**A valid Content Credential proves the pixels weren't changed. It can't tell a stranger whether to trust the signer.**

A C2PA manifest carries a cryptographic claim signature: a `COSE_Sign1` with the signer's full X.509 chain embedded in-band ([RFC 9360](https://www.rfc-editor.org/rfc/rfc9360) `x5chain`). Any verifier can confirm, with *no network call*, that the asset's bits weren't altered since signing. What it can't answer is the question that actually decides trust: *should I trust this signer?* Today that answer lives in a coalition-curated Trust List, or nowhere. Whisper closes that gap with one primitive: the signer's address *is* its identity, a publicly verifiable, DNSSEC/DANE-anchored, revocable name for the signer your manifest already references. This page is the content front door to the Whisper docs. The full technical library (DNSSEC, DANE, RDAP, the control-plane API) sits one click down the sidebar, identical to [whisper.online/docs](https://whisper.online/docs).

## The problem: "unknown source", and no Let's Encrypt for C2PA

A C2PA validator trusts a signer only if its certificate is on an explicit *allowed* list, or chains to a root on a *trust-anchors* list. The spec is deliberately unopinionated about which list: trust lists and anchors are **pluggable configuration inputs to the validator**. But in practice one list dominates: the official **C2PA Trust List + Conformance Program** (launched mid-2025), a coalition-curated set of CA anchors gated by a Product Security Architecture submission and assurance levels 1/2. Content signed by a certificate *off* that list renders as **"unknown source"**, technically identical, in the manifest, to a manifest from a verified organization. The burden shifts entirely to the verifier to resolve *who* the signer is, and there is **no free, automated, ACME-style path** for an independent creator, a small newsroom, a stringer, or an AI agent to become a recognized signer; commercial C2PA certificates run on the order of **~$289/yr**. The gap has a widely-used name: *there is no Let's Encrypt for C2PA*.

This is not a bug Whisper invented a story around. It is **C2PA's own stated dependency**. The spec says trust rests on "an identity ecosystem substantiating the signing key belongs to the Signer." C2PA provides the signature format and a curated CA list; it does *not* provide that public identity ecosystem. Two more edges sharpen it:

- **Revocation is optional and weak.** C2PA makes revocation *checking* optional; academic testing found conforming validators accepting revoked or compromised certificates and returning contradictory verdicts, and privacy pressure pushed the ecosystem away from CRLs toward optional OCSP, so a compromised signer can stay "trusted" long after the theft.
- **C2PA's own answer isn't DNSSEC.** Its experimental *Web Domain Trust Anchor* uses a self-signed certificate served from an HTTPS `/.well-known/c2pa.json` file, and its own write-up flags **domain-takeover** and validator-fetch **privacy** as open problems. A file fetched over plain HTTPS is exactly what a domain takeover subverts.

And there is no feedback loop. Because the whole chain travels in the manifest, verification needs no network call, so once content is published, the signer has **zero visibility** into who verified it, where, or how often.

**Honest scope, up front.** Anchoring the signer does *not* stop a screenshot or a heavy re-encode from separating the credential. That is watermarking's and durable soft-binding's job, and Whisper pairs with them rather than replacing them. It does *not* make signed content *true*: provenance is origin and history, not veracity, and a genuine signer can sign a photograph of a screen. And it is *not* a deepfake detector: the absence of a credential is not proof of fakery. What Whisper adds is the one layer none of these give you: a publicly verifiable, revocable *signer identity*, plus the analytics to see who checked it.

## The cure: the address is the signer

> **Shipped & live.** Deriving a signer `/128` from the C2PA signing key it already holds, with the signer-cert serial as `device_id`, DNSSEC + DANE-EE pinned and RDAP-registered, is in production today. Provision one with the control-plane call below, then verify it from the DNSSEC root with tools already on your machine.

Whisper gives each signer a routable IPv6 `/128` out of `2a04:2a01::/32` (announced by **AS219419**), derived *deterministically* from the signer's **public key**: the `SubjectPublicKeyInfo` of the C2PA claim-signer EE certificate (or a CAWG identity credential's key), with the **signer-cert serial** as the domain separator. The private key never leaves the signer's HSM or key store; only its public SPKI is an input. The result is [DNSSEC](/docs/dnssec)-anchored, [DANE-EE `3 1 1`](/docs/dane) pinned, and [RDAP](/docs/rdap)-registered, re-derivable and verifiable by anyone with `dig`. Publish that same EE certificate as a **DANE TLSA** record under your *own* DNSSEC-signed domain and the signer becomes **self-verifying**: any relying party can pin it with no central list to join, no gatekeeper, and no annual CA fee. That's the missing "Let's Encrypt for provenance."

```
signer's C2PA EE key          ──derive · domain-sep = cert serial──▶   /128                     ──DNSSEC + DANE-EE 3 1 1──▶   a signer anyone can verify
COSE signer cert · SPKI                                                2a04:2a01:c2a::51              (under your own domain)      whisper verify --trustless
cert serial = device_id                                               routable, tenant-bound        RDAP under AS219419          a pluggable anchor, via CAWG
(private key stays with the signer)                                   serial alone yields nothing                                op:'revoke' → gone at DNS-TTL
```

**A legitimate, pluggable trust anchor: additive, never a fork.** Because C2PA treats trust lists and anchors as validator configuration inputs, a DNSSEC/DANE anchor is a legitimate *alternative* trust source, not a re-invention of the standard. The manifest stays yours; the signer becomes publicly verifiable. Be candid about one thing, though: **DNSSEC/DANE is not (yet) a formally recognized C2PA *conformance* trust anchor.** Today conformance centers on X.509 and the curated C2PA Trust List. The clean way to surface it in-ecosystem is through **CAWG**: the Creator Assertions identity assertion carries a `did:web` issuer and a `cawg.web_site` URI that are already DNS-native, so a Whisper DNSSEC-anchored domain is a first-class `did:web` root. DANE-bind your `cawg.web_site.uri` and your `cawg.x509.cose` organization certificate and you turn a *well-formed-but-unrooted* identity into a *trusted* one without an S/MIME CA. It also directly answers C2PA's own *Web Domain Trust Anchor* experiment, with the mechanism that proposal didn't use: a DNSSEC-signed record instead of an HTTPS file a domain takeover subverts.

Because the derivation is **tenant-bound**, the same signing key under two different organizations yields two unrelated `/128`s. No outsider can link a signer across a publisher, a syndication partner, and a stock agency. And because the domain separator is the cert serial, **the serial alone yields nothing**: you cannot go serial → `/128` without the key, there is no enumerable directory, and RDAP and reverse-DNS return the registry object, never a map of who signs what.

What becomes true the moment a signer holds one:

- **Cross-org signer trust with no list.** A newsroom can verify a *different* organization's signer with no shared private allow-list and no coalition membership. Two parties that trust the DNS root already share a way to verify each other.
- **Off-list signers stop being second-class.** An independent creator or a stringer publishes a DANE-anchored signer under their own domain and is publicly verifiable without the `~$289/yr` toll or a coalition slot. The documented C2PA equity gap, closed.
- **A stolen key's window collapses.** One `revoke` pulls the signer at DNS-TTL: the exposure shrinks from "until OCSP, if a validator even checks" to *minutes*. It bounds the damage; between theft and propagation, spec-valid fraud can still exist, so this is a dramatic reduction, not a zero.
- **Verification becomes observable.** A DNS/DANE-anchored signer generates lookups when it is checked, so you finally learn *who verified your content*.

**Additive, never a replacement.** Whisper complements the pieces the ecosystem already does well and does not touch: the C2PA manifest and its edit history, the CAWG identity assertion, the RFC 3161 TSA time-stamp that keeps a manifest valid past cert expiry, a durable watermark (SynthID, Meta Seal) or Durable Content Credentials that recover a binding after a strip, and in-camera hardware signing. Whisper does *not* create the manifest or embed the watermark. It **anchors the signer the manifest already references**, and adds the analytics and revocation the rest of the stack lacks. It maps cleanly to the EU AI Act's named technique, Recital 133's "cryptographic methods for proving provenance and authenticity of content," made *accessible to the public* via open DNS, without ever claiming to *make* anyone compliant. More in [EU AI Act · C2PA · ISO 22144](/docs/content-compliance).

## Provision a signer 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 base64 SPKI of your C2PA signing certificate and the `device_id` (the signer-cert serial, or a CAWG identity / `did:web`), and 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 C2PA signer cert key>',
  device_id:'03ac74f29e1b5580'   // the C2PA signer-cert serial; or a CAWG id, e.g. 'did:web:example-news.org'
}}) 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:'03ac74f29e1b5580'}}) 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:c2a::51",
    "fqdn":    "signer-03ac74f2.c2pa.<tenant>.agents.whisper.online",
    "wireguard": { /* peer, keys, allowed-ips */ }
  } }
```

The call is **idempotent, liberal in what it accepts, strict in what it returns**: re-running with the *same* key and `device_id` returns the *same* `/128`; a *different* `device_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, never an opaque 500. To publish the DANE record under your *own* newsroom or studio domain (so readers verify "signed by example-news.org"), prove the domain once with `op:'domain'` and issue the signer under it. See [C2PA · CAWG · newsroom](/docs/content-integrations).

> A first-class typed `--signer-cert` / `--cawg` argument is on the roadmap. Today, signer provisioning is the control-plane call above (which is live): pass your signer-cert serial or CAWG identity as `device_id`. 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)

Every signer identity is checkable with no key and no login, from the internet's own records. The `whisper` CLI does the full walk in one call:

```
whisper verify --trustless signer-03ac74f2.c2pa.<tenant>.agents.whisper.online

✓ DNSSEC chain valid to the IANA root
✓ DANE-EE (TLSA 3 1 1) leaf matches the signer's key
✓ 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. The **TLSA** record *is* the pin: the `3 1 1` is a SHA-256 of the signer cert's SubjectPublicKeyInfo, so a validator can match it against the key inside any manifest that signer produced:

```sh
# the DANE pin: the signer's key, published under a DNSSEC-signed name
dig +dnssec TLSA _443._tcp.signer-03ac74f2.c2pa.<tenant>.agents.whisper.online +short
# 3 1 1 9e1b5580f2a4c7e1e0b3…c8d21f  ; the SHA-256(SPKI) any validator pins to

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

# the address is the signer: forward-confirmed reverse DNS names it
dig -x 2a04:2a01:c2a::51 +short
# signer-03ac74f2.c2pa.<tenant>.agents.whisper.online.

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

None of these calls Whisper as an authority: `--trustless` re-derives the proof against the public DNSSEC root, exactly as any resolver could. This is the second, DNS-anchored proof that complements the certificate a manifest already carries: a relying party outside your community can confirm the signer without any pre-provisioned anchor. See [Verify an agent](/docs/verify) for the full keyless check and [DANE & TLSA](/docs/dane) for the pin, byte for byte.

## Revoke a compromised signer, worldwide

A stolen signing key, a decommissioned press, a device whose secure element was found vulnerable: 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:c2a::51'}})

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

This is the revocation the provenance stack lacks at the *identity* layer. When a camera vendor's authenticity service was found vulnerable in 2025, it had to **suspend the service and revoke its entire set of C2PA device certificates**: every unit in the field, model-wide, because trust was pinned per-*model*, not per-*unit*. Per-signer identities derived from each device's own key, DNSSEC/DANE-anchored and *individually* revocable, turn that into a one-unit action at DNS-TTL: revoke the compromised signer and leave the rest of the fleet trusted. Compromise one signer and you've compromised *that signer*, not your whole imprint.

Short of a full revoke, the same control plane **governs what each signer identity may reach**: `op:policy` and `op:firewall` set a **default-deny** egress allow-list per identity: permit your TSA and your publishing endpoints, block everything else, by name, CIDR, or port. `op:budget` caps an identity's traffic with a kill-switch. It constrains who a signing box can talk to and be reached by, choking exfil and abuse, without an inline chokepoint.

And nothing is issued or torn down in the dark. Every mint and every revoke lands in a public, append-only [RFC 6962 Merkle transparency log](/docs/transparency), Ed25519-signed and anchored to Bitcoin via OpenTimestamps: a non-repudiable issuance-and-revocation trail an EU AI Act auditor, a court, or a licensing partner can replay. *Honest status:* it is tamper-evident, signed, and Bitcoin-anchored today, but **not yet independently witnessed**. It speaks the C2SP `tlog-witness` protocol so an external witness can co-sign.

## Who verified: the loop C2PA structurally can't close

This is the capability nobody else in provenance can offer. Because a C2PA validator builds the entire chain from certificates carried *inside* the manifest, verification generates **no network call**, which is elegant, and which also means the signer is **blind**: once content is out, they never learn who checked it. Anchor the signer in DNS/DANE instead, and the act of verifying (resolving the identity's name, matching the TLSA record, querying RDAP) becomes traffic against Whisper's own authoritative DNS and RDAP. `op:lookups` hands that back to the owner.

```sh
# who resolved or RDAP-queried this signer identity: the owner-facing companion to op:logs
curl -s https://whisper.online/ip/2a04:2a01:c2a::51/lookups | jq

# or over the control plane, with your key
CALL whisper.agents({op:'lookups', args:{agent:'2a04:2a01:c2a::51'}})
```

It reads two ways: as a **reconnaissance signal** (an unusual burst of resolutions against a signer whose content isn't public yet, or against a signer being impersonated, is an early warning *before* the abuse spreads) and as **verification analytics**: which platforms and partners actually check your content, where it travelled, and where credentials were being validated (or conspicuously weren't). Where `op:logs` shows a signing box's *own* outbound activity, `op:lookups` shows the interest *in* it. Pair it with [signed outputs](/docs/sign-outputs) so an AI tool or agent signs its own C2PA claim under a Whisper-anchored identity, and both the provenance *and* the verification trail become yours. *(Whisper anchors the signer identity; you produce the C2PA/CAWG signature with your existing tooling. A turnkey Whisper-native signing helper is on the roadmap, below.)*

## Attribution: name whoever spoofed your identity

Identity stops the next forgery; the graph names the operator behind the abuse already in your logs. C2PA's own security model acknowledges **identity-assertion spoofing**: lift a valid identity assertion from one of your assets, embed it in a new asset, and falsely attribute new content to your brand. Whisper's attribution names the infrastructure behind that campaign. It survives IP rotation because it fingerprints the operator and the tooling, not the ephemeral egress IP. 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(\"34.90.x.x\")"}'
# operator fingerprinted across AWS / GCP / Azure; residential swarm collapsed by JA3/JA4
```

The read-only verbs, `identify`, `origins`, `walk`, `variants`, `history`, each return a reproducible, replayable JSON evidence chain your trust-and-safety desk, a fact-checker, and an ICC/OSINT evidentiary dossier can replay. More in [Graph & cognition](/docs/graph-api).

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

We label these honestly so you can plan against them, and we are especially careful about *signing*: Whisper anchors the signer identity; producing the C2PA/CAWG signature itself is your existing tooling's job today.

| Shipped & live | On the roadmap |
|---|---|
| Signer `/128` from the signer's key + `device_id` (C2PA signer-cert serial or a CAWG identity): DNSSEC + DANE-EE + RDAP; verify, revoke, `lookups` | A first-class typed `--signer-cert` / `--cawg` CLI+API argument (provision via the control-plane call today) |
| Control-plane provision, verify, revoke, `lookups` (who-verified), firewall / budget / policy; the attribution graph and the Merkle transparency log over the public API | A turnkey Whisper-native **sign-outputs** helper that emits the C2PA/CAWG signature for you (today you sign with your own C2PA tooling; Whisper anchors the signer) |
| The **Splunk**, **Microsoft Sentinel** and **OpenCTI** connectors (signed, replayable JSON → CEF / ECS fields) | **STIX 2.1 over TAXII** export; a formal DANE-anchor **C2PA conformance** submission (today the DANE anchor is surfaced via CAWG as a complementary identity ecosystem, *not* an approved C2PA Trust-List anchor) |

The integration guides below describe **proposed** integrations at the C2PA/CAWG and IP boundary, designed to complement the stack you already run (the C2PA manifest, watermarking, in-camera signing), not endorsed by any vendor, and never named against a specific publisher, platform, or device maker as a breach victim.

## The five Content guides

The content story, in depth. Each page is self-contained and copy-paste runnable.

- **[Signer & C2PA identity](/docs/signer-identity)**. Derive a routable `/128` from the C2PA signing key you already hold. Deterministic, tenant-bound, DNSSEC + DANE-EE pinned: the signer-identity spine, keyed to the signer-cert serial or a CAWG identity.
- **[Provenance-gap cure](/docs/provenance-gap-cure)**. Why an off-list signer shows "unknown source" and there's no Let's Encrypt for C2PA, and how a DANE-anchored signer under your own domain ends it. The trust-list gap, cured at the identity layer.
- **[C2PA · CAWG · newsroom](/docs/content-integrations)**. Proposed integrations at the manifest/IP boundary: surface a DANE anchor via a CAWG identity assertion, DANE-pin `cawg.web_site` and your `did:web` issuer, key a device signer to its cert serial. Complements, never replaces.
- **[EU AI Act · C2PA · ISO 22144](/docs/content-compliance)**. Map signer identity and verification evidence to EU AI Act Art.50(2) & Recital 133, the C2PA Trust Model, and ISO/IEC 22144, as a network primitive, not a binder, and never a claim to "make you compliant."
- **[Sign · verify · who-verified](/docs/content-recipes)**. Runnable recipes: anchor a newsroom signer under your own domain, verify a claimed signer in seconds, read who-verified analytics, and back-trace an impersonation campaign on the graph.

## The full technical library

Content 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 a signer forge-proof, byte for byte, no CA in the path.
- **[Control plane](/docs/control-plane)**. The full `whisper.agents` API (provision, connect, policy, logs, lookups, revoke) over the public endpoint.

---

← [For newsrooms & makers](https://content.whisper.online/for-newsrooms) · [Signer & C2PA identity →](/docs/signer-identity)
