# Equipment & ECU identity

**Give a machine or an ECU a routable IPv6 `/128` derived from the hardware key it already holds and its equipment PIN. The address *is* the machine: forge-proof, tenant-private, DNSSEC-anchored, and revocable by the owner in one publicly verifiable call.**

This is the spine of the agriculture vertical, and it is **shipped and live**. Everything else (the equipment-API-abuse cure, the agritech integrations, the compliance evidence) builds on the one idea below: a machine's network address stops being a disposable label a proxy can rotate and becomes a cryptographic fact only that machine's silicon can stand behind.

> Two tiers, per Postel's Law. **With no API key** anyone, including the farmer who owns the machine, can *verify* its identity from stock tools (`dig`, `curl`, RDAP) because the identity is public by design. **With your key** you *provision* and *govern*: mint the `/128`, source-bind its egress, pull its logs, and revoke it. Verification never needs an account; the control plane does.

## The address is the machine

Almost every farm-data backend authenticates a *claim*, never a *machine*. A bearer token, a static API-key header, a grower password: each says "the holder of this string may act," and a string travels. It can be phished, replayed, lifted from a reverse-engineered app, and carried to any IP on earth. That is the root cause behind the whole family of farm-platform abuses: organization enumeration, broken object-level authorization (BOLA), one operator quietly harvesting a whole co-op's agronomic data from a residential-proxy swarm.

Whisper closes the gap by making the **network address itself the credential**. A machine gets a real, routable `/128` out of `2a04:2a01::/32` (announced by AS219419) that is a deterministic function of the hardware key the device was born with and its equipment PIN. Because the address is *derived from* a key only that device holds, you cannot present a machine identity whose key you don't have.

One more thing the bus can't give you: on ISOBUS (ISO 11783 over J1939/CAN), a device identifies itself with a 64-bit `NAME`: manufacturer code, function, identity number. It is a self-declared claim, and AEF Guideline 040's ISOBUS security principles name exactly that class of gap. The derived `/128` is the same machine's cryptographically provable public counterpart, at the IP boundary where proof is possible.

## How the derivation works

The `/128` is not assigned from a pool and written into a database. It is *computed*, the same way on every node, from inputs the machine already has:

| Input | What it is | Where it lives |
|---|---|---|
| **Device public key** | the `SubjectPublicKeyInfo` (SPKI) of the key the device was born with: a secure-element or TPM key in the telematics gateway | the **public** half is submitted; the private key **never leaves the device** |
| **Equipment PIN** | the 17-character product identification number stamped on the frame, canonicalized (it shares the road-vehicle VIN's 17-character format, and rides in the `vin` argument today) | submitted with the request; the public index |
| **Implement / ECU serial** *(optional)* | a per-component domain separator, so one machine can hold many addressable identities | optional; omit it for a single per-machine address |

```
# inputs -> a stable, forge-proof interface identifier
derive( device public key,  PIN [, ECU serial],  your fleet )  -->  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:

- **Deterministic.** The same `(key, PIN[, ECU])` yields a byte-identical `/128` every time, on every server. A reconnecting machine re-derives its own address; both authoritative nodes mint the identical identity with zero replication between them.
- **Forge-proof.** The address is a function of a key only the device holds. An attacker with a PIN and even the device's *public* key still cannot become that machine.
- **Tenant-bound & fleet-unlinkable.** The same key+PIN under a *different* tenant produces a *different* address, so an outsider cannot derive or enumerate a machine's address in a fleet they don't control, and the classic serial-enumeration walk is a dead end.
- **Liberal in, strict out.** The identifier is accepted generously, whitespace stripped and case-folded, then held to exactly 17 characters in the standard alphabet (`A-H J-N P R-Z 0-9`; no `I`/`O`/`Q`). A malformed identifier fails closed with a clear message, never a silent wrong address.

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 device's leaf key directly. All of it is DNSSEC-signed to the IANA root and registered in [RDAP](/docs/rdap). See [DANE & TLSA](/docs/dane) and [DNSSEC](/docs/dnssec).

> **The private key never moves.** The device submits only its public SPKI. The server derives a public *address* from public inputs plus a server-side secret; it never sees, holds, or derives the machine's private key.

## Provision a machine identity

Provisioning is one control-plane call: `whisper.agents` with `op:'connect'`, `tier:'wireguard'`, the device's public SPKI, and the PIN. 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 device key>',
  vin:                 '1AGCM82633A004352'   // the 17-character equipment PIN rides here today
  // ecu_serial: 'RC-0007'   // optional: a distinct /128 per implement ECU
}}) YIELD op, ok, status, result, error
   RETURN op, ok, status, result, error
```

**With stock tools:** just `curl`, no Whisper software:

```sh
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>...', vin:'1AGCM82633A004352'}}) YIELD op, ok, status, result, error RETURN op, ok, status, result, error"}
JSON
```

```json
{
  "op": "connect", "ok": true, "status": 200,
  "result": {
    "tier":               "wireguard",
    "address":            "2a04:2a01:e5a7:41c9:a6f1:7b:9e2d:30c8",
    "fqdn":               "a6f1007b9e2d30c8.<tenant>.agents.whisper.online",
    "server_public_key":  "…",
    "endpoint":           "…:51820",
    "dns":                "2a04:2a01:0:53::53",
    "wireguard_config":   "[Interface]\nAddress = 2a04:2a01:e5a7:41c9:a6f1:7b:9e2d:30c8/128\n…"
  },
  "error": null
}
```

Drop the returned `wireguard_config` onto the machine's telematics gateway (or feed it to `wireproxy` for a no-root, userspace tunnel) and every packet it sends now sources from its own `/128`. See [Connect & egress](/docs/connect) and the [Control plane](/docs/control-plane) reference.

> The `whisper` CLI ships `create --register`, `verify --trustless`, `policy`, `logs`, and `kill --revoke`. A dedicated `--pin` flag is **on the roadmap, not shipped**. Provision machines today via the control-plane call above, which is live.

## Idempotent, with honest errors

| You send | You get |
|---|---|
| the **same** key + PIN again (same tenant) | the **same** `/128`: a re-derivation, not a new allocation |
| the same key with a **different** PIN (same tenant) | `409`: the reused identity is never silently re-pinned to a mismatched address |
| a **non-string** identifier (or `ecu_serial`) | `400` with a helpful `detail`, never an opaque `500` |
| a PIN without `identity_public_key` | `400`: a device derives its address from its *own* key |

## Verify: keyless, no account

Anyone (a platform allowlisting a sanctioned consumer, an auditor, a dealer, the farmer who owns the machine) can prove a machine's `/128` without a Whisper account:

```sh
# 1. Forward-confirmed reverse DNS
dig -x 2a04:2a01:e5a7:41c9:a6f1:7b:9e2d:30c8 +short
# a6f1007b9e2d30c8.<tenant>.agents.whisper.online.

# 2. The keyless verdict endpoint
curl -s https://whisper.online/verify-identity/2a04:2a01:e5a7:41c9:a6f1:7b:9e2d:30c8 | jq .
# { "is_whisper_agent": true, "dane_ok": true, "jws_ok": true, "evidence": { … } }

# 3. The registry record: RDAP, IP-anchored to the /128
curl -s https://whisper.online/ip/2a04:2a01:e5a7:41c9:a6f1:7b:9e2d:30c8 | jq '.handle, .parentHandle'

# 4. The full chain re-derived on YOUR machine, against the IANA root
whisper verify --trustless a6f1007b9e2d30c8.<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. The full seven-proof walk lives in [Verify an agent](/docs/verify).

## Revoke: worldwide, owner-thrown, in one call

```
CALL whisper.agents({op:'revoke', args:{agent:'2a04:2a01:e5a7:41c9:a6f1:7b:9e2d:30c8'}})

# prove it, zero Whisper software:
dig -x 2a04:2a01:e5a7:41c9:a6f1:7b:9e2d:30c8 +short           # -> nothing
curl -s https://whisper.online/verify-identity/2a04:2a01:e5a7:41c9:a6f1:7b:9e2d:30c8
# -> {"is_whisper_agent": false, ...}
```

Revocation isn't a database flag you have to trust; it's provable the same way the identity was. That's the difference between this and the kill-switches agriculture already knows: the act is taken by the registered holder and is publicly checkable, never a covert lockout. On resale, one `revoke` plus a re-register under the new owner moves the data trail with the title.

## Attribution: name whoever already scraped you

```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(\"203.0.113.45\")"}' | jq .
```

The read-only Cypher surface (`identify`, `origins`, `walk`, `variants`, `history`) runs over the same endpoint with your key. There is no `whisper identify` CLI subcommand; the call above is the interface, and it is live. Full verbs in [Graph & cognition](/docs/graph-api).

## Where this fits (and where it doesn't)

- **Secure element / TPM.** The device's birth key is the *input* to the derivation. Whisper adds a routable, DNSSEC/DANE-provable name on top of the silicon root of trust.
- **ISOBUS / AEF Guideline 040.** The 64-bit ISOBUS `NAME` stays the bus identity; the derived `/128` is its verifiable public counterpart at the IP boundary. Whisper issues no bus messages and never touches the J1939/CAN authenticator or TIM functional safety.
- **OEM equipment clouds.** The cloud stays the CA for its own mTLS. Whisper adds an *out-of-tenancy* identity any third party, a partner, an auditor, the farmer, can verify against DANE without cross-signing.
- **Where Whisper does not go.** Not inside the implement bus, not the drone's Part-89 Remote-ID broadcast, and not the machine's functional-safety path. The doorway, not the hitch.

For the compliance mapping (ISO 24882, AEF 040, the EU Data Act, Ag Data Transparent), see [Agriculture compliance](/docs/industries/agri/agriculture-compliance).

## Next

- [Equipment API-abuse cure](/docs/industries/agri/equipment-api-abuse-cure): this identity, applied to the exact grant-harvesting / BOLA problem it was built for
- [Agritech integrations](/docs/industries/agri/agritech-integrations): dropping the `/128` into farm platforms, ISOBUS, cross-brand exchange, drones and LPWAN
- [DANE & TLSA](/docs/dane): the byte-for-byte record that makes the address provable against the device key

---

← [Agriculture overview](/docs) · [Equipment API-abuse cure →](/docs/industries/agri/equipment-api-abuse-cure)
