Skip to content

Tutorial: Verify a Delegation Chain

This tutorial verifies a chain, then deliberately breaks each invariant to see the verifier reject it. No hardware needed.

1. Generate a valid chain

python scripts/gen_example_chain.py
ca2a verify-chain --chain examples/minimal/chain.json
# {"verified": true, "hops": 3, "leaf_scope": ["cap:read"]}

The chain grants admin at the root, narrows to read+write, then to read.

2. Break attenuation

Open examples/minimal/chain.json and add "cap:admin" to the scope of the last hop (the leaf held only cap:read). Re-run:

ca2a verify-chain --chain examples/minimal/chain.json
# {"verified": false, "code": "SCOPE_ESCALATION", ...}

The leaf claimed authority its parent did not hold. Regenerate to restore.

Regenerate, then change the parent_id of the middle hop to "nope":

ca2a verify-chain --chain examples/minimal/chain.json
# {"verified": false, "code": "BROKEN_DELEGATION_LINK", ...}

4. Tamper with a signed field

Regenerate, then change any signed field (for example a scope entry) without re-signing:

ca2a verify-chain --chain examples/minimal/chain.json
# {"verified": false, "code": "INVALID_CREDENTIAL", ...}

The signature no longer matches the canonical body.

5. Verify in code

from ca2a_verify import verify_chain_file
from ca2a_runtime.errors import CA2AError

try:
    result = verify_chain_file("examples/minimal/chain.json")
    print(f"verified {result.hops} hops, leaf scope {result.leaf_scope}")
except CA2AError as exc:
    print(f"rejected: {exc.code}: {exc}")

What you proved

You verified a chain of delegated authority, offline, without trusting whoever produced it. That is the property cA2A carries into the runtime peer path once attestation and sealing land.