RFC-AITP-0007
RFC-AITP-0007
Key Resolution
Document: RFC-AITP-0007 Version: 0.1.0-rc.3 Status: Release Candidate Depends on: RFC-AITP-0001 Core, RFC-AITP-0002 Identity, RFC-AITP-0003 Agent Manifest
Abstract
Key resolution is the process of obtaining the public key needed to verify a signature. AITP has two distinct resolution flows:
- Peer key resolution — used to verify a peer's envelope signature, Manifest signature, and peer-issued TCT signature. The peer's public key is resolved from the peer's Manifest.
- Identity-issuer key resolution — used to verify an identity proof (e.g. an OIDC JWT). The issuer's public keys are resolved via cache → pinned → well-known.
This RFC defines both flows.
1. Peer Key Resolution
The peer's public key is encoded in manifest.aid (specifically, the AID's <identifier> portion). Resolution sources:
1. Manifest cache (in-memory, TTL-backed by manifest.expires_at)
2. Inline manifest (received during the Mutual Handshake)
3. Well-known endpoint (https://<peer-host>/.well-known/aitp-manifest)Note. The numbering above lists the sources, not a strict priority order. The decision rules below override the linear list — in particular, an inline Manifest with a newer
published_atoverrides a cached one even when the cached Manifest is unexpired.
Implementations MUST:
- Treat the cached Manifest as authoritative until
expires_at. - Prefer the inline Manifest received in
MUTUAL_HELLO/MUTUAL_HELLO_ACKif it has a newerpublished_atthan the cached one (RFC-AITP-0004 §11.3). - Re-fetch from
well-knownwhen the cache is pastexpires_at.
A peer key resolution failure MUST result in KEY_RESOLUTION_FAILED.
2. Identity-Issuer Key Resolution
For OIDC identity bindings (RFC-AITP-0002 §2), the issuer's keys are resolved separately. Order:
1. Cache (in-memory, TTL-backed)
2. Pinned Keys (local trust_anchors configuration)
3. Well-known URL (network fetch)Resolution stops at the first success.
2.1 Cache
- Keys fetched from well-known URLs MUST be cached.
- Cache TTL: default
3600seconds, configurable. - Cache SHOULD be refreshed asynchronously before TTL expiry.
- Expired cache entries MUST NOT be used unless
offline_modeis enabled.
2.2 Pinned Keys
Pinned keys are statically configured in the local trust-anchor configuration. See RFC-AITP-0002 §4. Pinned keys are always preferred over network-fetched keys for the same issuer.
2.3 Well-known Endpoint
For OIDC issuers, key resolution MUST use the standard OIDC discovery flow:
- Fetch
https://<issuer>/.well-known/openid-configuration(HTTPS only). - Parse the response and extract the
jwks_urivalue. - Fetch the JWK Set from
jwks_uri(HTTPS only). - Use the keys (matching the JWT header's
kid) to verify the OIDC identity proof.
This makes AITP work with any standards-compliant OIDC provider without requiring the provider to publish an AITP-specific endpoint. The OIDC Core 1.0 and OIDC Discovery 1.0 specifications already define every step.
For non-OIDC AITP-native key publication (e.g. an internal identity service that does not implement OIDC discovery), implementations MAY also accept:
https://<issuer>/.well-known/aitp-keyswith response format:
{
"issuer": "https://auth.example.com",
"keys": [
{
"kid": "key-1",
"kty": "OKP",
"crv": "Ed25519",
"x": "<base64url-encoded-public-key>"
}
],
"published_at": 1711900000,
"expires_at": 1711990000
}When both endpoints are present, OIDC discovery (openid-configuration → jwks_uri) MUST be tried first; the AITP-native endpoint is a fallback for non-OIDC issuers only. All fetches MUST use HTTPS. Plain HTTP MUST be rejected.
Resolution decision logic. The endpoint-selection rule is a branch on whether the issuer is an OIDC issuer, NOT a linear priority list:
- If the issuer exposes
/.well-known/openid-configuration(HTTP 2xx and a parseable discovery document), it is an OIDC issuer. The implementation MUST follow the OIDC discovery flow above and MUST NOT consult/.well-known/aitp-keysfor that issuer in the same resolution attempt. - If the issuer does NOT expose
/.well-known/openid-configuration(non-2xx response, network error, or invalid discovery document), the implementation MAY fall back to/.well-known/aitp-keys. - If neither endpoint produces a usable key, resolution fails and the configured
key_resolution.fail_mode(§3) applies.
This branch structure prevents an attacker who controls a non-OIDC AITP-keys endpoint at an OIDC issuer's host from substituting their keys when OIDC discovery is reachable. Implementations that describe their resolution order as a flat list of sources (cache → pinned → aitp-keys → OIDC JWKS) MUST instead split the network step into the OIDC-vs-non-OIDC branch above.
3. Failure Handling
When an identity-issuer key resolution flow exhausts all sources, the agent applies the configured key_resolution.fail_mode (NOT revocation_policy.mode, which governs revocation lookup failures only):
| Mode | Behavior |
|---|---|
fail_closed | Reject the request. Return KEY_RESOLUTION_FAILED. |
fail_open | Allow the request. Log a warning. No capability restrictions. |
soft_fail | Allow the request with grants restricted to a configured safe subset. |
The two modes have different defaults and semantics: key_resolution.fail_mode defaults to fail_closed and applies when no key for the identity issuer can be obtained, while revocation_policy.mode (RFC-AITP-0008 §3.1) applies when a revocation list cannot be fetched. Operators MUST configure them independently. See schemas/json/aitp-trust-anchors.schema.json.
3.1 Soft-fail grant restriction
In soft_fail, when key resolution fails, the agent MUST restrict grants to exclude any capability marked as requiring verified identity in policy. The safe subset is deployment-configured. If no safe subset is configured, soft_fail MUST behave as fail_closed.
For peer-key resolution failures, soft_fail is not applicable. Without a peer's Manifest there is nothing to verify against; the handshake cannot proceed.
3.2 Soft-fail and identity verification
soft_fail applies only to grant issuance policy after the
counterparty's identity has been independently verified via at least one
of:
- a cached, still-valid issuer key from a prior successful fetch,
- a pinned issuer key from the local trust store, or
- a deployment-local trust context (e.g. a sidecar that has already authenticated the issuer out-of-band).
If none of these trust bases exist for the issuer in question, soft_fail
MUST behave as fail_closed. An unverified identity proof MUST NOT be
accepted under any fail mode. The safe-subset semantics in §3.1 govern
which grants survive soft-fail; they do NOT relax the identity check
itself.
For peer Manifest key resolution specifically (i.e. the peer-key flow
in §1, not the identity-issuer flow in §2), every fail_mode behaves as
fail_closed: if the peer's Manifest cannot be fetched and verified,
the handshake MUST fail regardless of the configured mode. There is no
safe subset when the peer's identity cannot be verified at all — soft-fail
is a degraded-but-still-authenticated state, not an unauthenticated one.
Security rationale. Treating "no trust basis" as soft-fail-allowed collapses the distinction between not knowing an issuer and trusting it to issue restricted grants. An attacker who can prevent a verifier from reaching any of the issuer-key sources could otherwise present arbitrary identity proofs and be granted the safe subset by default.
3.3 fail_open and identity verification
fail_open MUST NOT bypass cryptographic signature validation. It MAY
suppress network-resolution errors when an independent trust basis
already exists for the identity issuer — specifically a cached,
still-valid issuer key from a prior successful fetch or a pinned
issuer key from the local trust store (the same trust bases enumerated
in §3.2 for soft_fail). If no such key is available after applying
fail_open, the downstream signature check has nothing to verify
against and MUST fail: fail_open does not accept unverified identity
proofs; it only suppresses the network error that preceded the
(still-failing) signature check.
Stated as an invariant: under every key_resolution.fail_mode, an
identity proof MUST be verified against a key the verifier already
trusts (cache, pin, or out-of-band) — fail_open widens the
availability envelope around transient network failures, not the
identity envelope around unauthenticated peers.
Implementations MUST NOT offer fail_open as a production default. It
is appropriate only for deployments with pinned issuer keys where
network failures should not block handshakes — in that configuration the
pinned key is always available and the signature check always runs
against it. For all other deployments, fail_closed (the schema
default) or soft_fail are the appropriate choices.
Conformance. Implementations MUST NOT advertise fail_open as a
recommended or default mode in their conformance harness or operator
documentation. An implementation that permits an identity proof to be
accepted under fail_open without verifying its signature against a
cached or pinned issuer key is non-conformant, regardless of how the
upstream key-resolution error is reported.
4. Offline Mode
When offline_mode: true:
- Identity-issuer well-known endpoint resolution is skipped entirely.
- Only cache and pinned keys are consulted for identity issuers.
- For peer Manifests, only cached and inline Manifests are accepted; outbound
/.well-known/aitp-manifestfetches MUST NOT be made. - Implementations MUST set
offline_mode: truein air-gapped environments.
key_resolution:
offline_mode: true
cache_ttl_secs: 3600
fail_mode: fail_closed5. Security Considerations
- Both well-known endpoints (peer Manifest and identity-issuer keys) are trust roots. Servers MUST present a valid TLS certificate; clients MUST validate it.
- Cache poisoning is mitigated by HTTPS. Implementations SHOULD also verify a static fingerprint when available.
- An agent MUST NOT downgrade
fail_modebased on transient errors. The configured mode is the policy. - A peer cache MUST be invalidated when the cached Manifest's
expires_atpasses; serving an expired Manifest hides peer key rotation.