Chio/Docs

Agent Passports

Reference for the data structures and verification mechanics behind Chio's portable identity layer. The companion how-to guide walks through producing and presenting a passport in practice; this page covers the schema, the standards-native projections, and the offline verification path that ships in the portable kernel core.


did:chio Identifiers

Every subject in a passport is a did:chio identifier:

text
did:chio:{64-lowercase-hex-Ed25519-public-key}

The method-specific identifier is the lowercase hex form of an Ed25519 public key. Resolution is self-certifying: the public key is embedded in the identifier itself, so a verifier can check signatures with no registry lookup, no DID resolver, and no network call. Parsing rules in chio-did:

  • The string must start with did:chio:.
  • The suffix must be exactly 64 hexadecimal characters.
  • The decoded public key must be Ed25519. P-256 and other algorithms are rejected with DidError::UnsupportedKeyAlgorithm.

Resolution returns a W3C-compliant DID document with the embedded Ed25519 verification method (in multibase encoding) plus optional service endpoints:

chio-did/src/lib.rs
pub const RECEIPT_LOG_SERVICE_TYPE: &str = "ChioReceiptLogService";
pub const PASSPORT_STATUS_SERVICE_TYPE: &str = "ChioPassportStatusService";

Service endpoints are attached by the resolving environment, not the identifier itself. Two operators resolving the same did:chio can hand back different service URLs while sharing the same verification method.


Passport Schema

The native passport (schema tag chio.agent-passport.v1) is an unsigned bundle of independently verifiable credentials:

chio-credentials/src/passport.rs
pub struct AgentPassport {
    pub schema: String,                                         // chio.agent-passport.v1
    pub subject: String,                                        // did:chio of the agent
    pub credentials: Vec<ReputationCredential>,
    pub merkle_roots: Vec<String>,                              // receipt-log checkpoint roots
    pub enterprise_identity_provenance: Vec<EnterpriseIdentityProvenance>,
    pub issued_at: String,                                      // RFC 3339
    pub valid_until: String,                                    // RFC 3339
    pub trust_tier: Option<TrustTier>,                          // optional, recent addition
}

The passport itself carries no signature. Trust comes from the credentials inside it: each ReputationCredential is independently signed by an issuer, and verification walks the bundle credential by credential.

The four field groups serve different verification needs:

FieldPurpose
subjectBinds the passport to a single Ed25519 keypair via did:chio
credentialsIssuer-signed reputation attestations carrying scorecards
merkle_rootsReceipt-log checkpoint roots so a verifier can spot-check receipt evidence
enterprise_identity_provenanceFederation evidence: which IdP authenticated the principal that issued each credential

Verifiable Credential Projections

Chio supports three wire formats for a passport. The native format is the source of truth; the other two are projections derived from it for interop with W3C Verifiable Credentials tooling.

FormatWhere it livesUse case
Native CHIO JSONchio-credentials/src/passport.rsSource of truth. All other formats are derived from this.
SD-JWT VCportable_sd_jwt.rsIETF SD-JWT-VC. Holders selectively disclose individual claims.
JWT VC JSONportable_jwt_vc.rsW3C VC 2.0 in JWT-encoded JSON for VP-style flows.

The SD-JWT VC projection partitions claims into two groups: always-disclosed claims that travel in cleartext, and selectively disclosable claims that the holder reveals on demand.

Always disclosedWhy
issThe credential issuer (the issuing operator)
subHolder thumbprint (binds to the holder's key)
vctVerifiable Credential type (the chio-passport SD-JWT VC type)
cnfConfirmation key (holder JWK for DPoP-style binding)
chio_passport_idStable passport identifier
chio_subject_diddid:chio of the agent the passport binds to
chio_credential_countNumber of credentials inside the bundled passport
Selectively disclosableWhy
chio_issuer_didsList of issuer did:chios for the credentials in the bundle
chio_merkle_rootsReceipt-log checkpoint roots referenced by the credentials
chio_enterprise_identity_provenanceFederation evidence (IdP, principal, tenant, groups, roles)

Selective disclosure is a presentation concern

Selectively disclosable claims travel as salted hashes in the compact SD-JWT. The holder reveals individual disclosures during presentation, so a verifier can be told which issuer signed the bundle without learning the federation provenance, or vice versa.

Multi-Issuer Composition

A passport can carry credentials from any number of issuers. Two organizations can each independently sign a credential for the same agent, and the agent bundles both into a single passport without either issuer needing to coordinate with the other.

This works because the passport is just a container: each credential carries its own Ed25519 proof, and verification walks the credentials individually. The PassportVerification result returned by verify_agent_passport exposes both lists:

chio-credentials/src/passport.rs
pub struct PassportVerification {
    pub passport_id: String,
    pub subject: String,
    pub issuers: Vec<String>,        // unique issuer did:chios
    pub issuer_count: usize,
    pub credential_count: usize,
    pub merkle_root_count: usize,
    pub enterprise_identity_provenance: Vec<EnterpriseIdentityProvenance>,
    pub passport_lifecycle: Option<PassportLifecycleResolution>,
    pub verified_at: u64,
    pub valid_until: String,
}

A verifier policy (see PassportVerifierPolicy in chio-credentials/src/policy.rs) can require credentials from a specific issuer allowlist or set a minimum issuer count before accepting the passport.


Offline Verification (Phase 20.1)

The portable kernel core ships an offline-capable passport verifier at chio-kernel-core/src/passport_verify.rs. It is no_std + alloc, so the same verifier compiles into native sidecars, browser WASM, mobile runtimes, and edge proxies.

The portable verifier consumes a thin PortablePassportEnvelope (schema tag chio.portable-agent-passport.v1) that wraps canonical-JSON bytes of any passport projection:

chio-kernel-core/src/passport_verify.rs
pub struct PortablePassportBody {
    pub schema: String,                  // chio.portable-agent-passport.v1
    pub subject: String,
    pub issuer: PublicKey,
    pub issued_at: u64,
    pub expires_at: u64,
    pub payload_canonical_bytes: Vec<u8>, // hex-encoded on the wire
}

pub struct PortablePassportEnvelope {
    pub body: PortablePassportBody,
    pub signature: Signature,
}

verify_passport performs four checks:

  • The bytes parse as a PortablePassportEnvelope and the schema tag matches.
  • The issuer key is in the relying party's authority key set.
  • The Ed25519 signature is valid over the canonical JSON of the body.
  • The clock value sits in [issued_at, expires_at).

On success it returns a VerifiedPassport with the subject, issuer, validity bounds, evaluation time, and the canonical payload bytes. There is no revocation lookup, no issuer-chain validation, and no payload decoding in the portable path. Those richer checks remain in the native chio-credentials / chio-kernel code; the portable core is the trust primitive that browsers and edge adapters can run with the same Ed25519 path the sidecar uses.


Holder Binding

A passport binds to runtime key material through the holder's confirmation key. In the SD-JWT VC projection the cnf claim carries a JWK for the holder's Ed25519 key (the same key embedded in chio_subject_did). The holder's thumbprint is the SD-JWT's sub, so the issuer signature attests that this passport may only be presented by the holder of the bound key.

At runtime, the same key signs DPoP proofs on the request side. A relying party that accepts a passport plus a DPoP proof has cross- bound evidence: the passport says "this scorecard belongs to the holder of did:chio:7b...", and the DPoP proof says "this request was signed by the same key".


Worked Example: Two-Issuer Passport

Agent did:chio:7b... has been operating across two orgs: Operator A (security tools) and Operator B (data tools). Each observes its own slice of receipts and signs an issuer-specific scorecard.

two-issuer-passport.json
{
  "schema": "chio.agent-passport.v1",
  "subject": "did:chio:7b0f6f63...",
  "credentials": [
    {
      "issuer": "did:chio:a1b2...",
      "credentialSubject": {
        "id": "did:chio:7b0f6f63...",
        "metrics": { "reliability": { "score": { "state": "known", "value": 0.97 } } }
      },
      "evidence": { "receipt_count": 5400, "checkpoint_roots": ["sha256:..."] },
      "proof": { "type": "Ed25519Signature2020", "proofValue": "..." }
    },
    {
      "issuer": "did:chio:c3d4...",
      "credentialSubject": {
        "id": "did:chio:7b0f6f63...",
        "metrics": { "reliability": { "score": { "state": "known", "value": 0.93 } } }
      },
      "evidence": { "receipt_count": 1820, "checkpoint_roots": ["sha256:..."] },
      "proof": { "type": "Ed25519Signature2020", "proofValue": "..." }
    }
  ],
  "merkle_roots": ["sha256:roota...", "sha256:rootb..."],
  "enterprise_identity_provenance": [
    { "provider_id": "operator-a-okta", "provider_kind": "okta", "principal": "agent-7b@org-a", ... },
    { "provider_id": "operator-b-azure", "provider_kind": "azure-ad", "principal": "svc-7b@org-b", ... }
  ],
  "issued_at": "2026-04-20T00:00:00Z",
  "valid_until": "2026-07-20T00:00:00Z"
}

A relying party Org C verifies the passport offline:

  • Parse the passport and confirm subject == did:chio:7b0f6f63....
  • For each credential, verify the Ed25519 proof against the issuer's embedded key (issuer is itself a did:chio, so the public key is in the identifier).
  • Confirm the credential subject equals the passport subject.
  • Apply Org C's PassportVerifierPolicy: for example, require both Operator A and Operator B in the allowlist, require min_receipt_count = 1000 per credential, and require active passport lifecycle.

Org C now has cross-issuer evidence about the agent without ever contacting Operator A or Operator B. The verification result lists both issuers and both provenance records, which Org C's downstream policy can attenuate independently.


How This Differs from the How-To Guide

The page at /docs/guides/agent-passport is task-oriented: it walks through creating a passport, presenting it, and writing a verifier policy. This page is a reference: it documents the schema, the projections, the selective-disclosure partitioning, the multi-issuer composition rules, and the portable-kernel offline verification path. Cross-link both directions when working through an integration.


Agent Passports · Chio Docs