Chio/Docs
LOGIN · JOIN

Operator Identity & Key Bindings

Tell a partner's kernel id, passport key, and transport endpoint apart, and see which check binds each one at your door.

Concept chio@5f63e6e

On this page

A partner's kernel reaches yours under three identities, and your kernel binds each one with a different check. Knowing which check holds which identity tells you exactly where a forged or misrouted message stops.

The partner card is where the bindings start. It carries the partner's org DID, trust-control URL, authority key history, receipt-signer keys, and status resolve URL, and chio partner add pins the partner's kernel key from it. The three checks that bind a partner's identities all answer to that pin.

Peer identitiesChoose a binding.
Their operatorYour operatorK′kernel iddid:chio:<hex>σpassport keykeyid = sha256(pk)eendpoint idEd25519 · irohKYour kernelTheir operatorYour operatorK′kernel iddid:chio:<hex>σpassport keykeyid = sha256(pk)eendpoint idEd25519 · irohKYour kernel

The handshake pins the passport key to the kernel id

The kernel id is an opaque string, did:chio:<hex> by convention. The handshake checks the declared kernel id first, then pins the declared passport key to it as a FederationPeer. The key is named by keyid = sha256(passport public key). Peer handshake.

One partner's three identities, the binding between each pair, and the lanes of the optional iroh transport that check them at your kernel. The kernel id form is the convention, and key values are left abstract. Mutual TLS and signed bodies on the default HTTPS transport are left out.

One partner presents a kernel id, a passport key, and an endpoint

Each identity names the partner at a different layer, and each is pinned by a different record on your side.

  • Kernel id. An opaque string, did:chio:<hex> by convention. The peer handshake pins a declared key to it and keeps the pin as a FederationPeer.
  • Passport signing key. The partner's long-term operator key, named by keyid = sha256(passport public key). Adding the card pins it; the handshake and the verifier's peer pins check every signature against it.
  • Transport endpoint id. The iroh Ed25519 endpoint key. The transport directory entry binds it to the kernel id, endorsed by the passport key.

The handshake checks the declared kernel id first, then the key. The directory binding matters only on the optional iroh lane; the default HTTPS transport authenticates each crossing with mutual TLS or a signature over the body.

Read more in Peer Pins & Trust Bundles, which covers how pins persist and rotate.

A did:chio identifier is its own public key

A did:chio identity uses an Ed25519 keypair, and the method encodes the public key directly into the identifier. Resolution is a local derivation, with no registry lookup and no network call.

did:chio formattext
did:chio:{64-hex-character-ed25519-public-key}

Example:
did:chio:bff663535a5cf58658cc38595d20dc4501f6dfc076ddf07e20571d413a3ceb5a

Because the method-specific identifier is the key, a party that knows the DID verifies signatures with it without contacting another service. Federating two operators needs no shared identity provider. chio did resolve produces the document from the key alone:

Resolve a did:chio documenttranscript
$ chio did resolve \
    --public-key 3cdb65ef41fc1f109bcedbd8cfbd792e0851c6f2acbe5008576400bf91d04d09 \
    --receipt-log-url https://trust.org-a.example/v1/receipts
{
  "@context": "https://www.w3.org/ns/did/v1",
  "id": "did:chio:3cdb65ef41fc1f109bcedbd8cfbd792e0851c6f2acbe5008576400bf91d04d09",
  "verificationMethod": [
    {
      "id": "did:chio:3cdb65ef41fc1f109bcedbd8cfbd792e0851c6f2acbe5008576400bf91d04d09#key-1",
      "type": "Ed25519VerificationKey2020",
      "controller": "did:chio:3cdb65ef41fc1f109bcedbd8cfbd792e0851c6f2acbe5008576400bf91d04d09",
      "publicKeyMultibase": "z6MkiYpYWyUNXHzHZsgmMPy4xypRKqdJjgnmAmNMtN2DDTBW"
    }
  ],
  "authentication": [
    "did:chio:3cdb65ef41fc1f109bcedbd8cfbd792e0851c6f2acbe5008576400bf91d04d09#key-1"
  ],
  "assertionMethod": [
    "did:chio:3cdb65ef41fc1f109bcedbd8cfbd792e0851c6f2acbe5008576400bf91d04d09#key-1"
  ],
  "service": [
    {
      "id": "did:chio:3cdb65ef41fc1f109bcedbd8cfbd792e0851c6f2acbe5008576400bf91d04d09#receipt-log",
      "type": "ChioReceiptLogService",
      "serviceEndpoint": "https://trust.org-a.example/v1/receipts"
    }
  ]
}
exit 0

The resolved document is deterministic:

  • @context points at the W3C DID v1 context.
  • One verificationMethod entry, #key-1, of type Ed25519VerificationKey2020, with its publicKeyMultibase in base58btc.
  • authentication and assertionMethod both reference #key-1.
  • Optional ChioReceiptLogService entries point at the operator's receipt query endpoint, so a counterparty can pull downstream evidence.

Passing --did with the fully qualified identifier in place of --public-key produces the same document. Omitting --receipt-log-url omits the service array and leaves the rest unchanged.

The passport key anchors every binding the partner signs

Resolving a DID tells you which public key belongs to an identifier. Whether your kernel recognizes that key for the relationship is your trust store's decision, made when you add the partner's card. From then on, the handshake checks the partner against the pinned key, and the transport directory endorses each endpoint under it. Every verifier on your side reads the same pin, and chio trust pins shows where it came from:

Terminalbash
chio trust pins --role receipt-kernel
Output
name     role            key                source
partner  receipt-kernel  ed25519:9b07…d31c  partner card, did:chio:z6MkpA7…c2T
file     ~/.chio/trust.toml

A key that never arrived on a card has no row here, however valid its DID document, and the handshake refuses it with MissingTrustAnchor or UnexpectedPeerKey.

A projected Agent Passport credential can bind to did:web, did:key, or did:jwk for portability. did:chio stays the provenance anchor in every projection, carried in chio_subject_did and chio_issuer_dids, so a verifier can trace any projection back to the key it pinned.

Read more in Agent Passports, which covers the credential model, its projections, claim families, and disclosure rules.

Each iroh lane checks the binding its frames depend on

On the optional iroh lane, the authenticated QUIC connection supplies an endpoint id. The three lanes turn that endpoint into a trusted sender in three ways:

  • Signals. The receiver resolves the authenticated endpoint id to a kernel id through the signed directory. The per-frame verifier then requires every frame's kernel id to match that sender, and each deposit verifies under its agent's passport key. A deposit signed with a kernel key is refused as KernelKeyUsedForDeposit.
  • Revocation. The wire types carry only a signer_id. The receiver projects that signer's key from the issuer-signed transport directory, requires the signer to be pinned to the authenticated endpoint, and verifies every root against it.
  • Co-sign. The accepting kernel binds the authenticated endpoint id to the kernel id the requester claims before it co-signs. A request that claims a different kernel id is refused, and no signature is produced.

Signals is the public name for the pheromone layer; the lane keeps the pheromone name in its ALPN. An endpoint the directory does not bind to an admitted kernel id never reaches any of the three.

Sources for the lane bindings

The "Per-Lane Identity Bindings Differ" section of docs/adr/ADR-0014-iroh-federation-transport.md, and crates/trust/chio-federation-transport-iroh/src/lanes/bilateral.rs in the Chio repository.

Read more in Transport Lanes, which documents each lane's frames and verifier.

A broken binding names the check that refused it

Each binding fails with its own code, so the refusal tells you which identity disagreed with your pins.

  • KernelIdMismatch comes from the handshake when the declared kernel id is not the one the caller expected. It is checked before any pin lookup.
  • UnexpectedPeerKey comes from the handshake when the declared key differs from the pin, and MissingTrustAnchor when no pin or trust anchor exists for the peer at all.
  • PeerUnpinnedOrKeyidMismatch comes from the bilateral verifier when a predicate's kernel id is unpinned, when its declared passport key fingerprint differs from the pinned key's, or when the resolved receipt's kernel key differs from the pinned tool_server_b key.
  • QUIC application error code 403 with reason not admitted comes from the transport gate when the endpoint is not bound to an admitted kernel id, before any lane handler runs.

Read more in Federation Refusal Codes, which indexes every code.

Next: run the handshake that checks these pins