Skip to content

spec: DelegationCredential has no validity period #108

Description

@aeoess

Problem statement

#36 has two MUST-level cases that can't be written yet: a delegation credential that's
expired, and one that isn't valid yet.

Neither can be represented today. DelegationCredential signs credential_id, issuer,
subject, scope, depth and parent_id. Nothing says when the grant starts or ends, so
chain verification can check structure and scope narrowing but can't decide whether the grant
covers an evaluation time.

I looked at agent-manifest first, since the delegation-chain doc says these semantics mirror
it. It's further along, and it stops one step short:

  • every hop signs delegated_at
  • scope_grant can carry ttl_seconds
  • the verifier rejects a child TTL longer than its parent's
  • nothing evaluates delegated_at + ttl_seconds against a clock

So the signed data an interval needs is already present there and unused. cA2A has its own
credential shape and its own verify_chain, with no temporal field at all.

Proposed solution

Give the credential an issuer-signed validity period:

  • a child's period is contained in its parent's
  • a child that starts before its parent or outlives it is a structural chain failure, next to
    SCOPE_ESCALATION
  • a structurally valid credential outside its own period is an authorization failure at
    evaluation time, with separate expired and not-yet-valid codes
  • verification takes the evaluation time as an argument, so vectors don't depend on the
    machine clock
  • structural offline verification can stay time-unchecked, runtime authorization has to
    evaluate the period

Two shapes are reasonable:

  1. delegated_at plus ttl_seconds, matching the agent-manifest hop
  2. an absolute window, not_before and expires_at

I lean toward one hop-level shape shared by both implementations. I don't have a strong view
on which field names win, but the two repos agreeing on one meaning matters more than the
choice does.

One detail affects the #36 boundary. In the conformance suite, _verify_action_evidence maps
every CA2AError out of structural verification to provenance_invalid. If the active-at
check runs inside that structural path, an expired credential classifies as provenance rather
than authorization, so the check probably belongs in the authorization step or behind its own
call.

Alternatives considered

A detached issuer-signed validity record bound to the credential digest keeps existing
credential bytes unchanged. The cost is a second signed object, plus rules for carrying it,
for it being absent, and for more than one turning up.

The holder challenge already expires, but that proves recent control of the holder key. It
doesn't show the issuer's grant is still live.

Revocation ends a grant early. It can't express a future start, and an offline verifier still
needs current revocation state.

Compatibility

DelegationCredential.from_dict rejects unknown and missing fields against a fixed field set,
so this breaks in both directions: today's verifier rejects a credential carrying a new
member, and a verifier expecting the new member rejects every existing credential.

That makes it a signed version or profile rather than a field addition. v1 canonical bytes and
fixtures stay frozen, unsupported versions fail closed, and mixed-version chains need an
explicit rule.

Security/TEE impact

No TEE change.

The validity check should run immediately before authorization or dispatch. Checking only when
the chain is loaded leaves a window where the credential expires before the action runs.

Spec alignment

No trace-spec change required. This touches the delegation credential spec, the error-code
list, the runtime authorization path, and the DELEG and ACTION conformance groups.

Once the shape is settled I can write the vectors: active, not yet valid, expired, inverted
and zero-length periods, child starting before its parent, child ending after its parent, both
exact boundaries, mixed versions, and the time-encoding cases that split implementations.

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-review:HIGHContributor check flagged HIGH risk

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions