| Internet-Draft | A2A Trust | September 2026 |
| Trujillo | Expires 8 March 2027 | [Page] |
This document defines a trust model for agent-to-agent (A2A) interactions in multi-agent AI systems. It specifies how agents obtain verifiable identities via CA-signed templates, how spawn chains are cryptographically established and validated, how dynamic policies are governed under a dual-signature model, and how cross-organizational agent interactions are explicitly authorized. The model applies existing PKI primitives (X.509, CRL, CSR) and established identity patterns (OAuth 2.0, On-Behalf-Of) to the problem of agent provenance. This document does not address agent-to-resource access control, human-in-the-loop orchestration, or agent behavior, as those concerns belong to the resource enforcement layer and the orchestration layer respectively.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 8 March 2027.¶
Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.¶
Multi-agent AI systems introduce identity and authorization gaps that existing standards do not fully address. When Agent A spawns Agent B, and Agent B calls a resource, no current standard defines how the resource verifies that Agent B was legitimately spawned, that its scope has not been escalated, or that its origin template is trusted.¶
This document proposes a trust model based on:¶
The model reuses proven PKI primitives and applies them to a new surface -- agent identity -- rather than inventing new cryptographic mechanisms.¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.¶
Every document defined by this specification -- the Agent Template extension of Section 8.2, the Agent Spawn extension of Section 10.5, the dynamic policy document of Section 11.4, the cross-organizational grant of Section 13.2, and the audit log entry of Section 10.4 -- is a JSON object serialized using the JSON Canonicalization Scheme (JCS) [RFC8785].¶
Field names in the tables of this document are display names, written for a reader. The corresponding wire names are lowercase, use underscore as the word separator, and are given in Table 3. A relying party MUST compare wire names exactly and MUST NOT apply case folding, Unicode normalization, or any other transformation before comparison.¶
The same rule governs every string value this document compares for equality: an agent identifier, an Owner, an OrgID, a Grantor or Grantee, a scope, a nonce, an outcome. Two values are equal when their octets are identical, and a relying party MUST NOT apply case folding, Unicode normalization, trimming, or any other transformation to either before comparing them. Where a later section restates this for one value, it does so for emphasis, not because the rule differs there.¶
A JSON object carried under this specification MUST NOT contain a duplicate member name, which [RFC8785], Section 3.1, also requires of any input to JCS. A relying party MUST detect a duplicate and refuse the document. This is a requirement on the parser, not only on the document: JSON syntax permits duplicates, and a parser that silently keeps the first or the last occurrence does not satisfy it. Two such parsers disagree about what was signed while both report success, which is the failure this rule exists to prevent.¶
Every timestamp carried under this specification is an [RFC3339] date-time in UTC using the Z designator. A relying party MUST refuse a timestamp carrying a numeric offset, a lowercase designator, or no designator: a time is compared byte-for-byte in a signed body, and one instant with two spellings is two instants to a signature. Fractional seconds MAY be present.¶
The JSON objects this document defines are flat. Their members are strings, integers, or arrays of strings, as the tables specify, and nothing else. A relying party MUST refuse an object carrying a nested object, an array of anything other than strings, a null, a boolean, or a non-integer number, before any further processing. A parser that will accept only the shapes this document defines has no depth to exhaust and no type to confuse.¶
A signed document is carried inside an envelope: a JSON object whose members are the signed document itself and the values that attest to it. The envelope members are named as follows. These names are REQUIRED; a relying party MUST refuse an envelope carrying any member not listed here.¶
| Member | Type | Content |
|---|---|---|
| body | object | The signed document: a template, a policy, or a grant |
| owner_sig | string | Signature by the template Owner |
| pa_sig | string | Signature by the Policy Authority |
| content_hash | string | SHA-256 digest of the signed octets, lowercase hexadecimal. REQUIRED in the envelope of a dynamic policy document; MUST be absent from the envelope of a template or a grant (Section 11.6) |
Every signature, and the content hash, is computed over the same octet string: the JCS serialization of body, and nothing else. The other envelope members are outside body and therefore never inside a preimage. A signature cannot cover itself, and an implementation that signs the whole envelope produces a value no verifier can reproduce. The rule that a document carrying an undefined field MUST be refused applies to body; the envelope members are not fields of the document they attest to.¶
Each signature member MUST be a string containing the base64 encoding [RFC4648] of the raw signature value, without line breaks and without PEM framing. A relying party MUST refuse an envelope whose owner_sig and pa_sig verify under the same public key: the subjectPublicKeyInfo of the Owner certificate and of the Policy Authority certificate MUST differ. Two roles satisfied by one key is one role. The comparison is of keys, not of signature octets: a randomized signature scheme produces different octets from one key on every signing, so equal signatures would never be observed even when a single key holds both roles.¶
The signature algorithm is determined by the type of the signer's public key, as carried in the signer's certificate, and is not signalled in the envelope. A signer MUST use, and a relying party MUST verify with, exactly the algorithm this table assigns; any other combination MUST be refused.¶
| Signer key | Algorithm | Signature value |
|---|---|---|
| RSA, 3072 bits or more | RSASSA-PSS with SHA-256, MGF1 with SHA-256, salt length 32 octets | The PSS signature octets |
| EC, curve P-256 | ECDSA with SHA-256 | r and s, each 32 octets, concatenated: 64 octets |
| EC, curve P-384 | ECDSA with SHA-384 | r and s, each 48 octets, concatenated: 96 octets |
| Ed25519 | Ed25519 (PureEdDSA) [RFC8032] | The 64-octet EdDSA signature |
Fixing the digest to the key type is what allows the envelope to carry no algorithm identifier: a verifier learns everything it needs from the certificate it has already validated, and an attacker cannot negotiate a weaker algorithm because there is nothing to negotiate. ECDSA values are the fixed-width concatenation rather than DER, so that a signature has exactly one encoding. RSASSA-PSS is specified rather than RSASSA-PKCS1-v1_5 because PSS carries a security proof and is the scheme new profiles adopt; a relying party MUST refuse a PKCS1-v1_5 signature even when it verifies. PSS is randomized: the same key and body produce a different signature on each signing, so a test vector verifies a signature rather than comparing its octets.¶
The following table gives the wire name for every display name used in this document. Where a display name appears in more than one document it has the same wire name in each.¶
| Display name | Wire name | Defined in |
|---|---|---|
| Subject | subject | Sections 8.1, 11.4 |
| Owner | owner | Sections 8.1, 11.4 |
| OrgID | org_id | Sections 8.1, 11.4 |
| PermittedOperations | permitted_operations | Section 8.1 |
| AllowedScopes | allowed_scopes | Sections 8.1, 13.2 |
| CanSpawn | can_spawn | Section 8.1 |
| MaxChildren | max_children | Section 8.1 |
| PolicyRef | policy_ref | Section 8.1 |
| TTL | ttl_seconds | Sections 8.1, 13.2 |
| Scopes | scopes | Section 11.4 |
| SpawnTargets | spawn_targets | Section 11.4 |
| Version | version | Section 11.4 |
| IssuedAt | issued_at | Sections 11.4, 13.2 |
| NotAfter | not_after | Section 11.4 |
| Grantor | grantor | Section 13.2 |
| Grantee | grantee | Section 13.2 |
| Template | template | Section 13.2 |
| MaxSpawns | max_spawns | Section 13.2 |
| GrantID | grant_id | Sections 13.2, 10.5 |
| ParentAgentID | parent_agent_id | Section 10.5 |
| SpawnedAt | spawned_at | Section 10.5 |
| SpawnNonce | spawn_nonce | Section 10.5 |
The Template Registry and the Template Registry CA are described as one logical entity throughout this document -- "the Registry" -- that stores templates, evaluates spawn requests, and issues certificates. A deployment may separate them; the interface between them is outside this document, and every requirement placed on "the Registry" applies to that entity as a whole.¶
Multi-agent orchestration creates identity and authorization gaps:¶
Agent A --> spawns --> Agent B --> calls --> Resource
The author is not aware of a standard, from the W3C, the IETF, or a vendor, that fully addresses agent provenance in multi-hop chains.¶
Several systems address a neighbouring problem. Workload identity frameworks such as SPIFFE [SPIFFE] issue verifiable identities to services but do not model one service spawning another under a bounded delegation. Relationship-based authorization systems such as OpenFGA [OpenFGA] evaluate what an identity may do but assume the identity is already established. PKI secrets engines such as Vault [VAULTPKI] issue certificates on request but leave the content of a certificate to the requester. This document assumes the zero-trust posture of [NIST800-207], in which no request is trusted for where it came from, and applies it to the question those systems leave open: how an agent proves what authority it was granted, and by whom.¶
Microsoft Entra ID OBO provides user-to-service delegation:¶
User --> Agent A (token A) --> Agent A requests token for Agent B on behalf of user --> Entra validates the chain --> Issues scoped delegated token
Key insight: a trusted third party validates the delegation chain. Agents do not self-assert trust.¶
OBO breaks down for agent-to-agent because agents are ephemeral, agent spawning is dynamic, and no registry exists for agent templates.¶
OAuth 2.0 [RFC6749] Token Exchange [RFC8693] defines scope constraint across delegation hops -- downstream tokens MUST be a subset of upstream grants. This document adopts that principle for agent scope inheritance.¶
Agent identity MUST be established using X.509 certificate chains [RFC5280]. This reuses the same trust model used by TLS and existing workload identity systems.¶
Certificates used for agent identity MUST conform to [RFC5280]. In addition, a relying party validating an agent certificate MUST enforce all of the following, and MUST refuse the certificate if any is not satisfied:¶
An agent certificate asserting cA = TRUE is a certificate entitled to issue further certificates. Such an agent can create children without presenting a request to the Template Registry CA, which removes both checks required by Section 10.1 from the spawn path entirely. No signature is invalid in that scenario and no chain fails to verify; the containment described in Section 8 is simply never consulted. This is the reason the constraint is stated normatively here rather than left to the general RFC 5280 profile.¶
These requirements are necessary and not sufficient. A certificate satisfying all of them establishes identity only; it carries no authorization. See Section 19.6.¶
An agent has exactly one identity, expressed as a UUID in the canonical lowercase textual form defined in [RFC9562]. A relying party MUST refuse a certificate whose subject common name is absent, is not a well-formed UUID in that form, or does not match the agent identifier the presenting party claims. Uppercase hexadecimal MUST be refused rather than case-folded: the identifier is compared byte-for-byte in several places, and an implementation that folds in one of them and not another will accept a document another implementation refuses.¶
This document does not constrain which UUID version is used. Implementations SHOULD use version 4 where the time an agent was created should not be inferable from its identifier, and MAY use version 7 where time-ordered identifiers are wanted and that disclosure is acceptable. A version 7 identifier embeds a millisecond timestamp, and an agent identifier travels to places its template does not -- audit records, policy references, diagnostic messages -- so the disclosure is wider than the certificate's own notBefore field.¶
Where a chain document restates that identifier alongside the certificate, every restatement MUST be identical to the subject common name, and a relying party MUST refuse the document if any two disagree. An implementation MUST NOT treat one restatement as authoritative and the others as advisory.¶
This requirement exists because a restated identifier that no signature covers is an unsigned claim sitting next to a signed one. Without this rule a chain could name one agent in the position a relying party reads and present a certificate issued to a different agent, and both artifacts would validate on their own terms.¶
Template Author
| defines template (scopes, spawn rules, TTL, owner)
v
Conformance gate (Section 9.1)
| every REQUIRED field present and non-null
v
Dual attestation (Section 9.2)
| Owner signs; Policy Authority countersigns
| the same JCS octets
v
CSR carrying the attested template
v
Template Registry CA (Section 9.3)
| re-applies the gate, re-verifies both signatures
| signs the template certificate
v
Signed Agent Template (registered)
|
v
Orchestrator spawns agent from signed template (Section 10)
| agent receives a certificate the CA issues from it
| CA chain proves provenance
v
Resource validates certificate chain:
- certificate issued by a trusted Template Registry CA?
- Agent Template extension present and well-formed?
- scope within bounds?
- ALLOW or DENY
Template Registry CA (root of trust)
|
| issues BOTH certificates (Section 9.3)
|
+--> Orchestrator Agent Certificate
| Subject CN: 9f3c... (a UUID, Section 7.2)
| Issuer: Template Registry CA
| Agent Template extension (Section 8.2):
| subject: 9f3c... (equals Subject CN, 9.3)
| owner, org_id
| permitted_operations: [spawn]
| allowed_scopes: [read:data, write:data]
| can_spawn: [2b7e...], max_children: 1
| policy_ref, ttl_seconds: 3600
|
+--> Child Agent Certificate
Subject CN: 2b7e... (a UUID)
Issuer: Template Registry CA
Agent Template extension:
subject: 2b7e...
allowed_scopes: [read:data] (subset, 10.3)
ttl_seconds: 900 (shorter, SHOULD)
Agent Spawn extension (Section 10.5):
parent_agent_id: 9f3c...
spawned_at, spawn_nonce
grant_id (only when spawned under a grant, 13.2)
An agent certificate never issues a certificate (Section 7.1).
The parent-child link is recorded in the child's Agent Spawn
extension; the chain of authority runs through the CA.
The following fields MUST be present in every agent template certificate and MUST NOT be modified without full re-certification:¶
| Field | Required | Description |
|---|---|---|
| Subject | REQUIRED | Unique template identifier |
| Owner | REQUIRED | Verified identity of template owner |
| OrgID | REQUIRED | CA-validated organization identifier |
| PermittedOperations | REQUIRED | Operations this agent may perform |
| AllowedScopes | REQUIRED | Maximum scopes this agent may hold |
| CanSpawn | REQUIRED | Whitelist of permitted child templates |
| MaxChildren | REQUIRED | Maximum concurrent child agents |
| PolicyRef | REQUIRED | Pointer to dynamic policy store |
| TTL | REQUIRED | Maximum agent lifetime |
This document defines one value of PermittedOperations: spawn, which an agent MUST hold to invoke Section 10. Any other value, including those shown in examples, is defined by the deployment and carries no meaning under this specification. A template whose CanSpawn is non-empty while its PermittedOperations omits spawn describes an agent permitted to spawn specific children and not permitted to spawn; the conformance gate of Section 9.1 SHOULD refuse it, and a Registry MUST refuse a spawn request from it.¶
A template defines exactly one agent (Section 4), so each entry of CanSpawn names a child that can exist at most once at a time, and MaxChildren counts named children rather than instances of one. MaxChildren MUST NOT exceed the number of entries in CanSpawn. The conformance gate of Section 9.1 MUST refuse a template that violates this, and a relying party MUST refuse a certificate whose extension does. A cap above the number of children a template can name is a cap on nothing, and a validator reading it would count toward a limit that can never be reached.¶
The certificate's issuer is not a template field. It is set by the Template Registry CA at issuance (Section 9.3) and read from the certificate (Section 8.2); a template carries no member for it.¶
The fields in Section 8.1 MUST be carried in a single X.509 certificate extension, identified by the object identifier 2.25.318754453516410815925104555075461256891 and referred to in this document as the Agent Template extension. The extension MUST be marked critical. A validator that does not implement this specification therefore refuses the certificate, as [RFC5280] requires of any unrecognized critical extension, rather than accepting it as an ordinary client certificate and granting whatever its issuer's chain would grant. The certificate is unusable except by a party that understands what it says, which is the fail-closed outcome Section 15.1 requires; an agent certificate has no legitimate use outside this specification.¶
The extnValue MUST be a DER OCTET STRING whose contents are the UTF-8 encoding of a JSON object, serialized as required by Section 3. A relying party MUST refuse a certificate whose Agent Template extension is not valid JCS, and MUST NOT attempt to repair or re-canonicalize it.¶
The JSON object MUST carry exactly the following members, all of which are REQUIRED. Wire names are as given in Table 3. A relying party MUST refuse a certificate whose Agent Template extension omits any member, carries a member not listed here, or carries a member whose type differs from the type given.¶
| Member | Type |
|---|---|
| subject | string |
| owner | string |
| org_id | string |
| permitted_operations | array of string |
| allowed_scopes | array of string |
| can_spawn | array of string |
| max_children | integer |
| policy_ref | string |
| ttl_seconds | integer |
The ttl_seconds member states a duration in seconds; the display name TTL in Section 8.1 does not carry a unit, and a duration whose unit is inferred is a duration two implementations will infer differently.¶
The certificate's issuer has no member in this extension. X.509 already carries the issuer, and a second copy inside an extension the issuer signs could disagree with the copy the relying party validated the signature against. A relying party MUST take the issuer from the certificate.¶
A certificate MUST NOT carry more than one Agent Template extension, and a relying party MUST refuse a certificate carrying two rather than choosing between them. The duplicate member rule of Section 3 applies, and is a requirement on the parser used to read the extension.¶
A relying party MUST impose a limit on the size of the extension before parsing it, and MUST refuse an extension exceeding that limit rather than attempting a partial parse. The limit is 16384 octets of extnValue for the Agent Template extension and 1024 octets for the Agent Spawn extension of Section 10.5. The first holds two hundred scopes at the maximum length of Section 10.3, which is more than any template this document contemplates; the second holds every member of a fixed-shape object with room to spare; and neither is large enough to be worth handing to a parser unverified. The extension arrives inside a certificate presented by the party whose authority it describes; it is attacker-controlled input up to the point the issuer's signature has been verified, and that signature covers whether the bytes were issued, not whether they are safe to parse. Implementations SHOULD verify the certificate signature before parsing the extension, so that malformed input from an unsigned certificate is discarded without being decoded at all.¶
Placing these fields in the certificate rather than in a document accompanying it is deliberate. Section 8.1 requires that they not change without re-certification. A field carried outside the certificate is signed by whoever assembled the document, not by the Template Registry CA, so an agent could present a valid certificate beside a template granting authority the CA never issued. Carrying them inside the certificate makes the immutability requirement a property of the artifact rather than a rule an implementation is asked to remember.¶
Dynamic policies MUST be bounded by the static template fields. A dynamic policy MUST NOT grant scopes beyond AllowedScopes. A dynamic policy MUST NOT add spawn targets beyond CanSpawn.¶
A relying party MUST evaluate these bounds itself, on every validation, against the static fields of the template certificate naming the subject the policy governs. This evaluation MUST be independent of signature validity -- a bounds violation is refused whether or not the signatures verify -- and it is performed after signature verification, in the order given by Section 11.7, so that a refusal under this section reports an authentic document whose content is not permitted. A policy exceeding the bounds MUST be refused before it is applied, however many valid signatures it carries.¶
The signatures required by Section 11.3 and the bounds required here answer different questions. The signatures establish who authorized a change. They do not, and cannot, establish that the change was within the ceiling the template set, because the ceiling is stated in a certificate that no signature over the policy covers. An implementation that treats a valid dual signature as sufficient authority to apply a policy has removed the only mechanism bounding what a policy may grant.¶
Refusal under this section is a distinct condition from a signature failure, and implementations SHOULD report it distinctly: the document is authentic and its content is not permitted. Reporting it as a signature failure misdirects the operator to the wrong lane of Section 11.1.¶
Every spawn MUST pass two independent checks. Either check failing MUST result in spawn denial with no fallback. The Template Registry performs both checks, as Section 10.2 specifies. That section lists the individual conditions in the order they are evaluated; this section states which check each condition belongs to, and an implementation MUST evaluate every condition of both.¶
Check 1 -- Static (from the spawning agent's certificate): The spawning agent's PermittedOperations MUST include spawn, the requested child template MUST appear in the spawning agent's CanSpawn list, and the requested scopes MUST be a subset of the spawning agent's AllowedScopes (Section 10.3). All three are read from the Agent Template extension of the spawning agent's certificate, never from a document the agent supplies. These are steps 1 and 4 of Section 10.2.¶
Check 2 -- Dynamic (Registry live lookup): The requested child template MUST be currently registered, CA-signed, not self-signed, not present in the current CRL, not DISABLED under Section 12.4, and owned either by the spawning agent's organization or by an organization that has issued a grant under Section 13 naming the spawning agent's organization as Grantee. The child template MUST also appear in the SpawnTargets of the dynamic policy currently in force for the spawning agent (Section 11.4), which the Registry retrieves through the PolicyRef of the spawning agent's certificate and never accepts from the agent; a policy with no SpawnTargets grants none, and an agent with no policy in force may not spawn. Finally the spawning agent's live child count MUST be below its MaxChildren. These are steps 2, 3 and 5 of Section 10.2.¶
Rationale: CanSpawn alone is insufficient because the certificate may be stale and a template may have been revoked since issuance. Registry lookup alone is insufficient because any party could forge a request claiming any template. The policy condition is what gives the fast lane of Section 11.1 authority over spawning: CanSpawn is the ceiling the certificate sets, SpawnTargets is what the Owner has currently authorized within it, and a spawn target can therefore be withdrawn by a policy change without re-certification. Both checks MUST pass.¶
1. CanSpawn check -- spawn in PermittedOperations, and
child template in CanSpawn list?
NO --> DENY, audit log
YES --> continue
2. Registry check -- child template registered, CA-signed,
not revoked, not DISABLED, and owned by the spawning
agent's organization or granted to it?
NO --> DENY, audit log
YES --> continue
3. Policy check -- child template in the SpawnTargets of
the policy in force for the spawning agent?
NO --> DENY, audit log
YES --> continue
4. Scope check -- requested scope subset of parent scopes?
NO --> DENY, audit log
YES --> continue
5. MaxChildren check -- current children < MaxChildren, and
no live certificate for the child template already?
NO --> DENY, audit log
YES --> spawn approved
6. Template Registry CA issues the child certificate with:
- parent identity embedded (delegation chain)
- scope equal to requested scope (not exceeding parent)
- spawn timestamp and nonce (replay prevention)
- grant identifier, when spawned under a grant
- audit log entry written
The count compared against MaxChildren in step 5 is held by the Template Registry, which is the only party that observes every spawn under a template. The Registry MUST perform that comparison as part of Check 2 of Section 10.1, atomically with recording the new child, so that two concurrent spawn requests cannot both observe a count one below the limit and both succeed. The second condition of step 5 follows from Section 12.1: a template defines one agent, one identity never holds two valid certificates, and the Registry MUST therefore refuse to spawn a child whose template already has an unexpired, unrevoked certificate. A relying party validating a chain document counts only the children that document names, and MUST refuse a document in which that count exceeds the parent's MaxChildren; that is a consistency check on the document, not the enforcement of the cap, and an implementation MUST NOT present it as such.¶
The Template Registry CA performs steps 1 through 5 and issues the certificate in step 6. The spawning agent presents a spawn request -- the child template's subject, the requested scopes, a timestamp, and a nonce per Section 19.2 -- and receives the issued certificate; it signs nothing, because Section 7.1 forbids an agent certificate from issuing. Steps 1 and 4 are evaluated against the spawning agent's own Agent Template extension, which the Registry reads from the certificate it presented. Step 3 is evaluated against the policy in force for the spawning agent, which the Registry retrieves through the PolicyRef of that extension; a policy the agent supplies with its request MUST NOT be consulted. If the policy store cannot be reached, or no policy is in force, the request is refused under Section 15.1.¶
A child agent's AllowedScopes MUST be a subset of the parent agent's AllowedScopes: every scope granted to the child MUST also be held by the parent. A child MUST NOT be granted any scope the parent does not itself hold; scope escalation across agent hops is explicitly prohibited. Equality is permitted -- a child MAY be granted the same scope set as its parent, or fewer.¶
Example:¶
Parent has: read:data, write:data Child gets: read:data -- valid Child gets: read:data, write:data -- valid (same as parent) Child gets: admin:data -- MUST be rejected
A scope is an opaque token. Two scopes are the same scope when their octets are identical, and a relying party MUST NOT apply case folding, Unicode normalization, prefix matching, wildcard expansion, or any hierarchy: write:data does not imply read:data, and admin:* names nothing. A scope MUST be between 1 and 64 octets, each from the set of lowercase ASCII letters, ASCII digits, colon, underscore, and hyphen. A relying party MUST refuse a document carrying a scope outside that syntax; the syntax is constrained so that byte comparison is also visual comparison, and a confusable character cannot name a scope that looks like another.¶
What a scope grants access to -- a secrets store, a data set, a tool -- is resource-layer authorization and is outside this document, as the Abstract states. This document bounds which scopes an agent may hold and how that bound narrows across a spawn; it does not define what any scope means. A deployment that needs to express "this agent may read vault A" does so with a scope such as secrets:vault-a:read, carried in allowed_scopes, bounded by the parent's allowed_scopes, and interpreted by the resource that owns vault A. The registry of Section 17.3 exists so that such names can eventually mean the same thing across organizations.¶
A collection of scopes is a set. The order in which its members appear is not significant to any comparison in this document, and a collection carrying the same scope twice is malformed and MUST be refused. The subset test above is therefore set containment, and two conforming implementations reach the same answer for the same two collections regardless of ordering. Order is significant only to serialization: [RFC8785] preserves array order, so the octets a signature covers depend on it. An implementation that reorders a collection before verifying it has changed those octets, and the signature fails; reordering is therefore not a normalization step. Comparison is performed on the parsed set, verification on the octets as received.¶
A request for no scopes MUST be refused. The empty set is a subset of every set, so an empty request satisfies the containment test vacuously while declaring no intent for the test to bound.¶
A child's ttl_seconds SHOULD NOT exceed its parent's. A delegation that outlives its delegator holds authority derived from an agent that no longer exists; the parent's certificate may be renewed, but a child sized to outlast it was sized on the assumption that it would not need to be.¶
Every spawn event, accepted or refused, MUST be recorded as an audit log entry: a JSON object carrying exactly the following members, subject to the presence rules the table states, serialized as Section 3 requires and hashed as Section 19.7 requires. The entry has no display names; wire names are given directly.¶
| Member | Type | Content |
|---|---|---|
| spawning_agent_id | string | Identifier of the spawning agent, in the form of Section 7.2 |
| child_template_id | string | Subject of the requested child template, in the same form |
| requested_scopes | array of string | The scopes the request asked for |
| granted_scopes | array of string | The scopes issued; empty when outcome is DENIED |
| spawn_nonce | string | The nonce of the request, per Section 19.2 |
| grant_id | string | The GrantID of Section 13.2 when the spawn was requested under a grant; MUST be absent otherwise |
| timestamp | string | The instant the Registry recorded the outcome, per [RFC3339], in UTC |
| outcome | string | ALLOWED or DENIED, exactly |
| reason | string | The step of Section 10.2 that refused the request, and why; REQUIRED when outcome is DENIED, MUST be absent otherwise |
| previous_hash | string | The entry_hash of the preceding entry, lowercase hexadecimal; sixty-four zero digits for the first entry of a log |
| entry_hash | string | SHA-256 over the canonical form of every other member of this entry, lowercase hexadecimal, per Section 19.7 |
A refused request is recorded for the same reason an accepted one is: a sequence of refusals is the evidence of an attempt, and a log that records only successes cannot show one.¶
Step 5 of Section 10.2 issues a child certificate carrying its parent's identity, the time of the spawn, and the nonce of the request that produced it. These MUST be carried in a single X.509 extension, marked critical for the reason given in Section 8.2, identified by the object identifier 2.25.316124730704531463413455892107752909312 and referred to in this document as the Agent Spawn extension. It is encoded exactly as the Agent Template extension of Section 8.2: a DER OCTET STRING containing the UTF-8 JCS serialization of a JSON object, subject to the same rules on criticality, duplicate members, duplicate extensions, size limits, and parse ordering.¶
| Member | Type | Content |
|---|---|---|
| parent_agent_id | string | The parent's identifier, in the form required by Section 7.2 |
| spawned_at | string | The instant of issuance, per [RFC3339], in UTC |
| spawn_nonce | string | The nonce of the spawn request, per Section 19.2 |
| grant_id | string | The GrantID of the grant under which the spawn was authorized (Section 13.2); REQUIRED when the child template is owned by an organization other than the spawning agent's, MUST be absent otherwise |
parent_agent_id, spawned_at and spawn_nonce are REQUIRED when the extension is present; grant_id is present exactly when the spawn was cross-organizational, and a relying party MUST refuse a certificate that carries it for a child owned by the parent's own organization or omits it for one that is not. A certificate for an agent that has a parent MUST carry the extension; a certificate for an agent that has none -- a root orchestrator -- MUST NOT. A relying party validating a chain MUST refuse a certificate whose parent_agent_id names no agent in the chain, MUST refuse one whose parent_agent_id differs from the parent the chain document names for it, and MUST refuse a root whose certificate carries the extension.¶
This is what makes a spawn chain cryptographically traceable rather than merely asserted. A parent identifier carried only in a chain document is an unsigned claim beside a signed certificate: a child could name any parent it liked, and the containment of Section 10.3 would be evaluated against whichever parent it chose. Carrying the link in the certificate means the CA that issued the child attested to which agent spawned it, and that attestation is what the scope and spawn checks are evaluated against.¶
The parent's Agent Template extension, not the child's Agent Spawn extension, is where the child's authority is bounded. The Agent Spawn extension says who the parent is; the parent's certificate says what the parent may delegate.¶
The absence of the Agent Spawn extension asserts that no agent spawned this one; it does not exempt the certificate from anything. A root is legitimate for the same reason any agent certificate is: it was issued by the Template Registry CA from a template attested under Section 9, and it chains to that CA under Section 7.1. No party can declare itself a root, because no party other than the CA can issue a certificate that validates, and the CA issues only from attested templates. A relying party verifies a root exactly as it verifies any other agent certificate.¶
spawned_at and spawn_nonce record the request the Registry accepted. The freshness window of Section 19.2 applies to that request, at the Registry, at the time it is made. A relying party validating an issued certificate later MUST NOT apply the window to spawned_at: a certificate an hour old is as valid as one a second old, and its currency is governed by its validity period and its revocation state, not by when it was requested. A relying party MUST, however, refuse a chain in which two certificates carry the same spawn_nonce. That is a consistency check on the document, in the sense Section 10.2 gives the term: what makes a nonce unique across every chain the Registry ever issues is that the Registry accepts each nonce once, under Section 19.2, and a relying party holding one chain cannot observe another. An implementation MUST NOT present the document-local check as the enforcement of uniqueness.¶
grant_id is what makes Section 13.4 enforceable. A grant can be revoked by its Grantor alone, and every certificate issued under it must then become untrusted; without a member naming the grant, nothing identifies those certificates. With it, the Registry that issued them can revoke them, and a relying party in either organization learns of it through the revocation state the certificate already points to.¶
Template certificate (static): WHO the agent is and WHO it can spawn. Changes require full re-certification.¶
Dynamic policy (fast lane): WHAT the agent can do within the bounds of the template certificate. Changes require dual signature (Section 11.3).¶
Dynamic policies MUST NOT exceed the bounds defined in the static template certificate.¶
Template ownership MUST be established at certificate signing time and embedded in the Owner and OrgID fields. Only the verified owner of the organization that signed the template MAY submit policy changes. Verified means holding the private key of the Owner certificate of Section 9.2, whose subject common name equals the template's Owner field; no other form of verification is defined by this document.¶
Every policy change MUST be signed by two independent parties:¶
Neither signature alone is sufficient. Both MUST be present and valid for a policy to be accepted.¶
Owner key + Policy Authority key = policy accepted
^ ^
who owns it passed the gates
A dynamic policy document MUST contain the following fields. This is the complete set; a document containing any other field MUST be refused, since an unrecognized field is either meaningless or an attempt to convey authority the profile does not define.¶
| Field | Type | Required | Description |
|---|---|---|---|
| Subject | string | REQUIRED | Identifier of the agent this policy governs; MUST match the Subject of the template certificate |
| Owner | string | REQUIRED | Submitting owner; MUST match Owner in the template certificate |
| OrgID | string | REQUIRED | Submitting organization; MUST match OrgID in the template certificate |
| Scopes | array of string | REQUIRED | Scopes granted by this policy; bounded by AllowedScopes |
| SpawnTargets | array of string | OPTIONAL | Spawn targets granted by this policy, each a template Subject in the form of Section 7.2; bounded by CanSpawn. Absent means none are granted, and a spawn request is then refused at step 3 of Section 10.2 |
| Version | integer | REQUIRED | Monotonically increasing integer, scoped to Subject |
| IssuedAt | string | REQUIRED | Timestamp of issuance, per [RFC3339] |
| NotAfter | string | OPTIONAL | Expiry of this policy, per [RFC3339]; MUST NOT be later than the notAfter of the certificate the policy governs. Absent means equal to it |
Version is scoped to the Subject, not global. A relying party MUST refuse a policy whose Version is not strictly greater than the Version of the policy currently in force for that Subject.¶
A policy is never valid beyond the notAfter of the certificate it governs, whether or not NotAfter is present. NotAfter can only shorten that period. A relying party MUST treat an absent NotAfter as equal to the certificate's notAfter, MUST refuse a policy whose NotAfter is later than it, and MUST refuse a policy presented after either has passed.¶
Signatures and hashes defined by this document are computed over bytes, so the mapping from a policy document to those bytes MUST be deterministic and identical across implementations.¶
Wherever this document requires a canonical form -- of a policy document, of any field subset thereof, or of an audit log entry -- that canonical form MUST be the JSON Canonicalization Scheme (JCS) serialization defined in [RFC8785]. A single canonical form is specified for all of them deliberately: an implementation carrying two serializations will eventually apply the wrong one, and the resulting failure presents as a signature or integrity error with no indication that serialization was the cause.¶
JCS is specified rather than described here because a bespoke serialization would require this document to define property ordering, string escaping, and number formatting correctly and completely, and any error in that definition surfaces to implementers as a signature failure that appears to be a cryptographic fault. Serializations that differ only in whitespace, key order, or the escaping of non-ASCII characters produce different bytes and therefore different signatures; implementers MUST NOT assume a language's default JSON encoder produces the canonical form, as most do not.¶
Both signatures required by Section 11.3 are computed over the preimage defined in Section 3.1: the canonical form (Section 11.5) of body. Because Section 11.4 makes its table the complete content of body, every field in that table is inside the preimage and none is excluded from either signature. This section and Section 3.1 describe the same octets.¶
In particular, Version MUST be inside the signed preimage. Version exists to prevent replay, and it cannot serve that purpose while it remains modifiable without invalidating a signature: an attacker holding no key can otherwise take a superseded but validly signed policy, increment its Version, and present it as current. Both signatures verify, the content hash matches, and the version reads as current. The same reasoning applies to Subject: a signature that does not bind the policy to the agent it governs permits a policy issued for one agent to be presented for another.¶
The content hash is a member of the envelope of a dynamic policy document only. It is REQUIRED there, because step 4 of Section 11.7 stores the policy and step 5 re-reads it, and a stored document wants an integrity value that is cheaper to check than two signatures; it MUST be absent from the envelope of a template or a grant, which are verified on presentation and whose signatures already cover the same octets. The content hash MUST be SHA-256, or a stronger digest, computed over the same canonical form and the same field set as the signatures. The hash field itself is stored alongside the policy document and MUST NOT be included in its own preimage. The content hash is a derived value: a relying party MUST recompute it from body and refuse the document on a mismatch, and MUST NOT use the envelope's content_hash as an input to any decision. A modified content_hash therefore causes a refusal and nothing else; it is not a value a signature needs to protect, because the signature already covers everything the hash summarizes.¶
The signatures and the content hash are carried in the envelope of Section 3.1, outside the policy document they attest to. A relying party MUST refuse a policy document that carries any of them as a policy field: they are not in Section 11.4, and a value inside body would be inside its own preimage.¶
1. Identity and ownership verification
- requester matches Owner in template certificate?
- requester OrgID matches certificate OrgID?
NO --> rejected, audit logged
2. Automated gate (policy engine):
- scope within AllowedScopes?
- spawn targets within CanSpawn?
- no conflicts with active policies?
ANY FAIL --> rejected
3. Dual signature applied:
Owner signs, Policy Authority countersigns
4. Policy stored with dual signature, version, timestamp,
and content hash
5. Relying party validates at runtime:
- both signatures valid?
- version current? (replay prevention)
- hash matches? (tamper detection)
- policy within template certificate bounds?
ANY FAIL --> DENY, audit logged
| Scenario | Single Sig Gap | Dual Sig Fix |
|---|---|---|
| Rogue Policy Authority | Pushes bad policy | Owner key missing |
| Rogue owner | Bypasses automated gates | PA won't countersign |
| Compromised owner key | Attacker modifies | Automated gates enforced |
| Compromised Policy Auth | Pushes bad policy | Owner key missing |
The table above concerns the dual signature. The following concerns the encodings this document specifies, and the attack each one closes.¶
| Scenario | Without the encoding | With it |
|---|---|---|
| Replayed Owner signature | An Owner signature over anything other than the policy body verifies for every later policy on that agent; a rogue Policy Authority reuses it | Both signatures cover the same body (Section 3.1); a signature is specific to one policy |
| Replayed policy | A superseded but validly signed policy is presented as current | Version is inside the preimage and must exceed the version in force (Section 11.4) |
| Swapped template | A valid certificate is presented beside a template granting authority the CA never issued | Static fields live in the certificate (Section 8.2); there is no separate template to swap |
| Forged parent | A child names whichever parent gives it the widest scope; containment is evaluated against that parent | The parent link is in the child's certificate, attested by the CA (Section 10.5) |
| Mismatched identity | A chain names one agent and presents a certificate issued to another; both validate on their own terms | Every restatement must equal the subject CN (Section 7.2) |
| Silent parser disagreement | Two parsers keep different duplicates of a key and both report success | Duplicate detection is a parser requirement (Section 3) |
| Unlocatable revocation | Revocation must be consulted but the certificate does not say where | cRLDistributionPoints or OCSP is required (Section 14.4) |
| Spawn under a revoked grant | A grant is revoked and nothing identifies the certificates issued under it | grant_id in the Agent Spawn extension; the issuing Registry revokes them (Section 13.4) |
| Spawn the policy withdrew | A policy grants no spawn targets and the agent spawns everything its certificate's CanSpawn allows | SpawnTargets is a step of the spawn sequence (Section 10.2) |
A new template version MUST undergo full re-verification from scratch. Trust MUST NOT be inherited from a previous version.¶
Rationale: inheriting trust from v1 would allow a compromised v1 certificate to bootstrap trust for v2.¶
A new version keeps the template's Subject and receives a new certificate. The Registry MUST revoke the prior certificate when it issues the new one, so that one identity never has two valid certificates; a relying party that encounters two unrevoked certificates for one Subject MUST refuse both.¶
Everything on the old template chain continues to work unchanged as long as the certificate is valid. New connections and functionality are opt-in -- only available after the new template chain is fully verified and explicitly adopted.¶
The following MUST NOT be inherited from a previous version:¶
DISABLED is a Registry state, not a revocation. It is reported by the Registry in Check 2 of Section 10.1 and is not carried in a CRL. Because only the Registry performs spawns, no other party needs to distinguish DISABLED from ACTIVE: a relying party validating an existing agent's certificate consults revocation state as usual, and an agent issued under a template that is later DISABLED remains valid until its TTL or its revocation.¶
Disable SHOULD precede delete. Implementations SHOULD enforce a mandatory waiting period between DISABLED and DELETED.¶
Cross-organizational grants MUST be explicitly re-issued for each new template version. Grants MUST NOT automatically roll over on version upgrade.¶
Cross-organizational agent spawning MUST be explicitly authorized by the resource-owning organization. No implicit trust exists between organizations.¶
A cross-organizational grant MUST contain exactly the following fields:¶
| Field | Type | Description |
|---|---|---|
| GrantID | string | Identifier of this grant: a UUID in the form of Section 7.2, unique among the grants the Grantor has issued |
| Grantor | string | OrgID of the resource-owning organization |
| Grantee | string | OrgID of the requesting organization |
| Template | string | Subject of the template granted, in the form of Section 7.2 |
| AllowedScopes | array of string | MUST be a subset of the template's AllowedScopes |
| IssuedAt | string | Instant of issuance, per [RFC3339], in UTC |
| TTL | integer | Grant validity period in seconds, counted from IssuedAt |
| MaxSpawns | integer | Maximum concurrent agents permitted under this grant |
Wire names are given in Table 3. A grant is signed as specified in Section 3.1, by the grantor's Owner and Policy Authority; the signatures are envelope members and are not fields of the grant.¶
A grant expires at IssuedAt plus TTL seconds. A relying party MUST refuse a grant whose expiry has passed, and MUST refuse one whose IssuedAt is later than its own clock by more than the freshness window of Section 19.2. A duration with no stated origin has no expiry two parties can agree on; IssuedAt is the origin.¶
A cross-organizational spawn is evaluated and issued by the Grantor's Registry, which owns the template and the CA that issues against it. That Registry holds the count compared against MaxSpawns and MUST enforce it atomically with recording the spawn, exactly as Section 10.2 requires of MaxChildren. The Grantee's organization performs no part of the issuance and cannot enforce the cap.¶
Which option applies is deployment policy. Under each, a relying party in the Grantee organization MUST hold a trust anchor for the Grantor's Template Registry CA and MUST validate the Grantor's Owner and Policy Authority certificates to it, as Section 9.2 requires, before accepting a grant's signatures. A grant whose signatures cannot be validated to a trust anchor the relying party holds MUST be refused.¶
The granting organization MAY revoke a cross-organizational grant without the cooperation of the receiving organization. Upon revocation, all agents spawned under the affected grant MUST be treated as untrusted on next validation. The Grantor's Registry issued every such certificate, and each carries the grant's GrantID in its Agent Spawn extension (Section 10.5). On revoking a grant the Registry MUST revoke, under Section 14, every unexpired certificate whose grant_id names it, and MUST refuse further spawn requests under it. A relying party in either organization then learns of the revocation through the revocation state the certificate itself points to (Section 14.4), and needs no channel to the Grantor beyond that.¶
Each organization MUST maintain its own independent audit trail. Audit records MUST NOT depend on the other organization's systems.¶
Template revocation MUST be performed by recording the template certificate as revoked in the CA's revocation state -- an X.509 CRL, an OCSP responder, or an equivalent revocation registry consulted on every validation. All agent certificates derived from a revoked template MUST be treated as untrusted on the next revocation check.¶
Individual agents MAY be revoked by explicit certificate revocation or, outside this document, by removal of authorization relationships at the resource layer.¶
Routine revocation (TTL expiry, task completion) MUST be fully automated. Human involvement SHOULD be reserved for incident response and high-impact decisions.¶
Every certificate issued under this specification, other than a self-signed trust anchor, MUST carry either the cRLDistributionPoints extension or the authorityInfoAccess extension with an id-ad-ocsp accessMethod, both as defined in [RFC5280]. A relying party MUST refuse a certificate carrying neither, because the obligation in Section 14.1 to consult revocation state on every validation cannot be discharged against a certificate that does not say where that state lives.¶
A relying party MUST NOT treat an unreachable revocation source as an absence of revocation. This restates Section 15.1 and is stated again here because it is the requirement implementations most often relax under operational pressure.¶
Any verification step that cannot be completed MUST result in DENY. This includes:¶
Implementations MUST NOT provide a degraded mode that allows partial spawning or execution when verification infrastructure is unavailable.¶
Implementations MUST place every field in the location specified by this document: Section 3, Section 8.2, Section 10.5, Section 11.4, Section 13.2, and Section 10.4. Variable placement is not permitted.¶
Non-conforming CSRs MUST be rejected by the CA. A non-conforming template MUST NOT be signed.¶
Implementations MUST provide test vectors -- concrete examples of valid and invalid template chains -- for conformance validation.¶
No conformance certification authority exists for this document. An implementation claiming conformance MUST state the revision it claims, as Section 18 describes, and SHOULD publish the results of running the test vectors of Section 16.3 against that revision. A claim without a stated revision is not a conformance claim.¶
A reference implementation SHOULD be made available including:¶
Known implementations are listed in Section 18.¶
The Agent Template extension of Section 8.2 and the Agent Spawn extension of Section 10.5 each use an object identifier under the joint-iso-itu-t UUID arc (2.25), which is self-assigning from a UUID and requires no registration. This document requests no allocation from any IANA-managed OID arc. Should this document be adopted, the author is willing to replace them with OIDs under an arc the responsible working group prefers.¶
IANA is requested to register the following media type in the "Media Types" registry, per [RFC6838].¶
IANA is requested to create a registry titled "A2A Agent Scopes", with a registration policy of Specification Required [RFC8126]. Each entry carries a scope name, a description, and a reference. The registry is initially empty; scope names not registered here are private to a deployment and MUST NOT be assumed to carry the same meaning across organizational boundaries.¶
This section records the status of known implementations of the protocol defined by this specification at the time of posting, as described in [RFC7942]. It is meant to assist the IETF in its decision processes in progressing drafts to RFCs. Please note that the listing of any individual implementation here does not imply endorsement by the IETF. Furthermore, no effort has been spent to verify the information presented here that was supplied by IETF contributors. This is not intended as, and must not be construed to be, a catalog of available implementations or their features. Readers are advised to note that other implementations may exist.¶
According to [RFC7942], "this will allow reviewers and working groups to assign due consideration to documents that have the benefit of running code, which may serve as evidence of valuable experimentation and feedback that have made the implemented protocols more mature. It is up to the individual working groups to use this information as they see fit."¶
This section is to be removed before publishing as an RFC.¶
Three independent implementations exist at the time of writing. Each states the revision it was written and verified against, and continues to state that revision until someone re-reads the newer text and re-runs the vectors. An implementation pinned to an earlier revision remains a correct implementation of that revision; a version string is a conformance claim rather than a label, and advancing one without re-verifying asserts conformance nobody has tested. Each is tagged in its repository at the commit implementing the revision named here.¶
| Implementation | Revision | Notes |
|---|---|---|
| a2a-trust-playground | -03 | Browser implementation, no installation or backend. Mints a Registry, attests and issues templates, and validates a chain against every check in this document, reporting the clause governing each refusal. Tagged impl/draft-03; the implementation of -02 remains retrievable at tag impl/draft-02. Source: https://github.com/tonyt68/a2a-trust-playground |
| ietf-a2a-trust-poc | -00 | Registry CA, spawn validation and policy governance services. Tagged impl/draft-00. Source: https://github.com/tonyt68/ietf-a2a-trust-poc |
| hack-my-own-code | -00 | Adversarial implementation that attacks its own conformance. Canonicalizes with a language-specific JSON serialization rather than the scheme required by Section 11.5, so it does not conform to that section. Tagged impl/draft-00. Source: https://github.com/tonyt68/hack-my-own-code |
All three are maintained by the author of this document. They are independent in the sense that they share no code and were written against the specification text rather than against each other; they are not independent in the sense [RFC7942] most values, and a reviewer should weigh them accordingly. An implementation by an unrelated party would be more informative than all three, and is actively sought.¶
Implementations MUST enforce at every hop that child agent scopes are a subset of parent scopes: child scopes are contained within parent scopes, and no scope may be introduced that the parent does not already hold. Failure to enforce this allows privilege escalation across the agent chain.¶
A spawn request MUST carry a timestamp and a nonce, both generated by the spawning agent. The timestamp MUST be an [RFC3339] instant in UTC. The nonce MUST be at least 128 bits of output from a cryptographically secure random number generator, encoded as base64 [RFC4648]. The nonce and timestamp of an accepted request are recorded in the child's Agent Spawn extension (Section 10.5); those of every request, accepted or refused, are recorded in the audit log entry of Section 10.4.¶
The Registry is the relying party for a spawn request. It MUST record the nonce when the request carrying it is received, before any step of Section 10.2 is evaluated, and MUST refuse a later request carrying the same nonce whatever became of the first. A nonce is spent by being presented, not by being accepted: a request refused at any step has consumed its nonce, and a retry MUST carry a fresh one. Recording only accepted nonces would let a refused request be replayed until something changed and it was accepted, and a fresh nonce costs nothing to generate.¶
A relying party MUST refuse a spawn request whose timestamp is more than 60 seconds from the relying party's own clock in either direction, and MUST refuse a request whose nonce it has already seen within that window. A relying party MUST retain seen nonces for at least twice the freshness window. Retaining them for exactly the window leaves a request replayable at the boundary, when the record has been discarded but the timestamp is still inside the window at the receiver.¶
The window is specified rather than left to the deployment because a value chosen independently at each end is not a shared window, and the wider of the two is the one an attacker gets. Accepting a request from the future by the same margin accommodates clock skew; an implementation that accepts only past timestamps will reject legitimate requests from a peer whose clock is marginally ahead. The window assumes clocks synchronized to within a small fraction of it. An operator whose clocks cannot meet that assumption MUST treat it as a failure condition under Section 15.1 rather than widen the window; a wider window is a longer replay opportunity for every party, not a fix for one party's clock.¶
Sixty seconds tolerates the skew of any correctly administered clock -- NTP holds hosts within milliseconds -- and bounds the nonce retention obligation of a Registry to two minutes. It is deliberately tighter than the five minutes Kerberos [RFC4120] adopted: that tolerance was sized for human-operated hosts with unsynchronized clocks, and a spawn request is a sub-second exchange between machines. A window sized for the former is a longer replay opportunity than the latter needs, and a peer whose clock is more than a minute wrong is not a peer to be accommodated.¶
A compromised template certificate MUST be revoked immediately. A single CRL update invalidates all downstream agent certificates derived from that template.¶
The dual signature requirement (Section 11.3) ensures no single compromised party can push unauthorized policy changes. CA compromise requires full ecosystem re-issuance.¶
Compromise of an Owner or Policy Authority key is handled by revoking its certificate under Section 14. Policies and templates signed under the compromised key MUST be re-signed under replacement keys, because a relying party cannot distinguish a signature made before the compromise from one made after it; a revoked signing certificate invalidates every signature it ever produced, not only the fraudulent ones.¶
Cross-organizational grants MUST be explicitly issued. Implicit trust between organizations is prohibited.¶
Because agent identity is carried in X.509 certificates and the chain is verified on every validation, it is natural to assume the certificate chain also constrains what an agent may do. It does not, and an implementation built on that assumption is unprotected while appearing rigorous.¶
X.509 carries no representation of the scopes defined by this document. AllowedScopes, CanSpawn and MaxChildren are conveyed in the template, and no certificate path validation algorithm inspects them. A conformant X.509 validator presented with an agent certificate whose associated template claims scopes far beyond those its parent holds will report success, because the certificate is genuinely valid and correctly issued. The over-scoping is not a defect the validator is looking for.¶
The nameConstraints extension does not close this gap. It constrains the namespace within which a CA may issue, not the authority a subject may claim once issued. Likewise certificatePolicies expresses which policies a chain supports, not whether a child exceeded its parent, and policy processing is disabled by default in common implementations.¶
Consequently Section 8.3 and Section 10.3 are load-bearing implementation logic. They are not restatements of a property the certificate chain already guarantees, and an implementation that omits them because "the chain verifies" has no containment at all. Certificate validity establishes identity. Authorization is evaluated separately, every time.¶
Audit logs MUST be tamper-evident. Logs MUST NOT be deletable by agents or orchestrators. Audit log infrastructure SHOULD be outside the control of the agent ecosystem itself.¶
Each entry's hash MUST be computed as SHA-256, or a stronger digest, over the canonical form (Section 11.5) of every member of Table 6 other than entry_hash -- that is, including previous_hash and excluding the entry's own hash. As with policy documents, an unspecified preimage is not a detail: two implementations hashing different field sets each read the other's chain as broken, and a chain that cannot be verified across implementations provides no evidence to anyone but its author.¶
The Owner member of a template is carried inside a certificate that is presented to every relying party the agent ever contacts. An Owner value that identifies a person -- an email address, as the examples in this document use for readability -- is therefore personal data disclosed to every counterparty. Deployments SHOULD populate Owner with an identifier that is opaque outside the owning organization, and resolve it to a person only within that organization.¶
A version 7 agent identifier discloses the agent's creation time to every party that sees the identifier, as Section 7.2 describes. Audit records required by Section 10.4 carry agent identifiers and scopes, and Section 13.5 places one such record in each organization party to a cross-organizational spawn; the OrgID of each is disclosed to the other by the grant itself.¶
The signature algorithms of Table 2 and the key strength floor of Section 7.1 are classical. This document does not specify a post-quantum signature algorithm, because no X.509 profile for one had reached the stability this document requires at the time of writing. The per-key-type mapping is the extension point: a future revision adds a row for a post-quantum key type without changing the envelope or any other structure, and a relying party that does not recognize a key type refuses the signature, which is the fail-closed outcome Section 15.1 requires.¶
Every document this specification defines reaches a relying party from the party whose authority it describes, and is attacker-controlled input until a signature over it has been verified. Section 8.2 states this for the two certificate extensions; it applies equally to a signature envelope, a chain document, and a grant. Three rules of this document exist for that reason and are restated here so that they are read as one defence. The shape rules of Section 3 -- flat objects, no duplicate members, exact wire names, a fixed member set -- mean a conforming parser accepts only the shapes this document defines and has nothing else to be confused by. The size limits of Section 8.2 bound what a parser is asked to read. And the ordering that section requires -- for a certificate, verify the issuer's signature before decoding an extension; for an envelope, verify the signatures over the body octets before acting on any member of body -- means input nobody signed is discarded before it is interpreted. A relying party that parses first and verifies afterwards has exposed its parser to every party able to present a certificate, which is every party.¶
As with the previous revision, every change here was surfaced by implementing the -02 text rather than by re-reading it. Three implementations of one specification produced three different answers to the same questions, which is what the changes below exist to prevent.¶
Section numbers in this appendix are those of draft-tonyai-a2a-trust-02, the revision these changes produced. Several sections were renumbered in -03; see Appendix A.¶
All changes in this revision were surfaced by building a second, independent implementation of the -01 text and attacking it. Changes are described below by their effect on a conformant implementation rather than by intent: where an implementation conforming to -01 must change to remain conformant, this is stated plainly, because an implementer reading this appendix is deciding whether re-verification is required.¶
Four changes below are breaking. Two implementations exist at the time of writing, both under the author's control; the cost of these changes is at its minimum now and rises permanently once a third-party implementation ships.¶
Security fix -- breaking.¶
Interoperability -- breaking.¶
New normative requirements -- additive.¶
Rename -- breaking.¶
Removal -- breaking for any implementation reading the field.¶
Non-normative.¶
Section numbers in this appendix are those of draft-tonyai-a2a-trust-01, the revision these changes produced.¶
Clarified two areas identified as ambiguous during development of a reference implementation:¶
Neither change alters the normative requirements themselves; both make explicit what the -00 text intended. Both were surfaced by building and red-teaming a conformance reference implementation against the -00 text.¶