diff --git a/adr/0010-did-anchored-identity-domainless-publishers.md b/adr/0010-did-anchored-identity-domainless-publishers.md new file mode 100644 index 0000000..df6541e --- /dev/null +++ b/adr/0010-did-anchored-identity-domainless-publishers.md @@ -0,0 +1,73 @@ +# ADR 0010: DID-Anchored Identity for Domainless Publishers + +## Status +Proposed + +## Context +The discovery identifier (§4.2.1) and the Trust Manifest authority-alignment +rule (§5.1) both require the `` namespace root to be a fully +qualified domain name (FQDN), verifiable against a cryptographic workload +identity (mTLS / SPIFFE SVID) issued by that domain. The rationale is sound for +DNS-anchored publishers (Appendix C): the FQDN is an immediate, decentralized +authority anchor that forecloses namespace-squatting. + +However, a growing class of publishers has no controllable domain — agents whose +identity is rooted in a [W3C Decentralized Identifier](https://www.w3.org/TR/did-core/) +(`did:plc`, `did:web`) and a signed personal data store. Today such a publisher +cannot appear in an ARD catalog at all: it can neither form a compliant +`urn:air:` identifier (no FQDN for the `` slot) nor satisfy §5.1's +FQDN-aligned attestation requirement. This is a real hole in ARD's identity +story, raised against this spec in +[ards-project/ard-spec#47](https://github.com/ards-project/ard-spec/issues/47). + +## Decision +Add a **DID-anchored branch** to the discovery identifier and a normative +resolution path, additively — the FQDN mainline is untouched. + +1. **URN branch (§4.2.1).** When the `` position carries the literal + token `did`, the identifier follows + `urn:air:did::::`. The + initial registered method set is **`did:plc` and `did:web` only**, with the + DID constrained to exactly three colon-segments + (`did::`); path-bearing `did:web` and further DID + methods are deferred to a later amendment. The existing + `ai-catalog.json` identifier pattern already admits this form, so no schema + change is required. +2. **Resolution path (§5.1.1).** A four-step normative procedure: resolve the + DID Document (`did:plc` → `plc.directory`, `did:web` → `/.well-known/did.json`), + select the `verificationMethod` (by JWS `kid`, else first compatible), verify + a detached JWS computed over the **JCS-canonicalized ([RFC 8785](https://www.rfc-editor.org/rfc/rfc8785))** + content, and reject on failure. +3. **Authority-alignment carve-out (§5.1).** For `identityType: "did"`, + authority-alignment is satisfied by verified DID control via §5.1.1; FQDN + alignment is not required. Additive language only — no rewrite of the FQDN + rule. + +Per maintainer guidance on #47, this ships as a single coupled change (URN branch ++ resolution path are interdependent and must merge together), and the +canonicalization choice is pinned to JCS rather than left implementation-defined. + +## Consequences +- Domainless `did:plc` / `did:web` publishers can publish ARD catalog entries + with cryptographically verifiable authority, without DNS or a cloud identity + provider. +- The five federation properties in Appendix C are preserved by the DID branch + (see new Appendix C.1); namespace-squatting remains foreclosed via DID control + instead of FQDN control. +- No change to the `ai-catalog.json` schema, CDDL, or conformance fixtures; the + existing `^urn:air:...` pattern already validates DID-anchored identifiers. +- A DID-control proof attests *who published*, never compliance or safety + (§7.2 unchanged). +- The Appendix C.1 wording is written to compose with the transport-side FQDN + pressure in [#24](https://github.com/ards-project/ard-spec/issues/24); a future + unified domainless-namespace amendment can subsume both. +- `did:key` / `did:peer` and path-bearing `did:web` remain unsupported until a + follow-up amendment, once the resolution machinery is validated against the + initial two-method set. + +## Companion work +[drknowhow/install-manifest-spec#37](https://github.com/drknowhow/install-manifest-spec/issues/37) +carries the artifact-side `publisher` block (optional `did` + detached JWS over +canonical manifest bytes) so an install-manifest can hold the publisher identity +binding this resolution path verifies. The same JCS canonicalization constraint +applies on both sides to keep one signing model. diff --git a/spec/ard.md b/spec/ard.md index d8f8e81..a4521bb 100644 --- a/spec/ard.md +++ b/spec/ard.md @@ -204,6 +204,27 @@ urn:air::: * **``**: Optional hierarchical segments separated by : (e.g., finance:trading, weather:telemetry). Allows publishers to categorize capabilities by department, team, or product line without altering infrastructure routing. * **``**: Mandatory terminal segment representing the specific, logical short name of the agent or tool (e.g., assistant, pptx-creator). +#### Domainless Publishers: the DID-Anchored Branch + +Publishers without a controllable fully qualified domain name — for example, agents whose identity is rooted in a [Decentralized Identifier (W3C DID)](https://www.w3.org/TR/did-core/) and a signed personal data store rather than in DNS — MAY substitute a DID for the `` FQDN. The `` position then carries a DID in place of a domain: + +``` +urn:air:did:::: +``` + +* The literal token `did` in the `` position signals the DID-anchored branch and distinguishes it unambiguously from an FQDN root (no registrable domain is the bare label `did`). +* In the initial registered set, `` MUST be one of `plc` or `web`, and the DID MUST occupy **exactly three** colon-delimited segments — `did::`. Accordingly, `did:web` is restricted to its host-only form (`did:web:`) in this branch; path-bearing `did:web` identifiers and additional DID methods (`did:key`, `did:peer`, …) are deferred to a future amendment so the resolution machinery can be validated against a small, fixed set first. +* `` (optional) and `` (mandatory terminal segment) retain exactly their meaning from the FQDN branch. + +Examples: + +``` +urn:air:did:plc:ewvi7nxzyoun6zhxrhs64oiz:mcp:memory-server +urn:air:did:web:example.com:weather:telemetry +``` + +Authority for a DID-anchored identifier is established by verified control of the DID — see [§5.1.1](#511-did-anchored-identity-resolution-domainless-publishers) — not by FQDN cross-reference against `trustManifest`. A `did:web` publisher that also controls a domain MAY appear under either branch; the two forms denote the same publisher when the `did:web` host equals the FQDN, which makes `did:web` a natural migration on-ramp between the branches. The existing `identifier` pattern in the `ai-catalog.json` schema already admits this branch (the DID's internal colons parse as additional segments), so no schema change is required. + #### Please see more details at [Architectural Rationale for URN Restriction](#appendix-c:-agent-naming-urn-format) ### 4.3 Host Info Object @@ -296,6 +317,32 @@ Discovery via GitHub Pages (combining the above): } ``` +#### The Domainless (DID-Anchored) Path + +Like the Solo Developer Path, but the publisher has no domain at all — identity is rooted in a `did:plc` and a signed personal data store. The discovery identifier uses the DID-anchored branch (§4.2.1); authority is proven by DID control (§5.1.1), and `trustManifest` carries the same DID with `identityType: "did"`. + +```json +{ + "specVersion": "1.0", + "host": { "displayName": "Yep", "identifier": "did:plc:ewvi7nxzyoun6zhxrhs64oiz" }, + "entries": [ + { + "identifier": "urn:air:did:plc:ewvi7nxzyoun6zhxrhs64oiz:mcp:memory-server", + "displayName": "Memory Server", + "type": "application/mcp-server-card+json", + "url": "https://example.dev/.well-known/mcp/memory-server.json", + "trustManifest": { + "identity": "did:plc:ewvi7nxzyoun6zhxrhs64oiz", + "identityType": "did", + "signature": "" + } + } + ] +} +``` + +No FQDN, no SPIFFE issuer, no cloud account: a consumer resolves `did:plc:ewvi7nxzyoun6zhxrhs64oiz` to its DID Document, validates the detached JWS against the published key, and accepts the entry as bound to that DID. + #### Enterprise Example Using trustManifest for compliance, published in a manifest. @@ -357,6 +404,21 @@ The trustManifest object sits alongside the artifact content in a catalog entry | provenance | Array | Optional. List of Provenance Link objects recording lineage. | | signature | String | Optional. Detached JWS signature computed over the Trust Manifest content. | +**Authority alignment for DID-anchored identities.** For `identityType: "did"`, the authority-alignment requirement on `identity` (above) is satisfied by verified control of the DID, established via the resolution path defined in [§5.1.1](#511-did-anchored-identity-resolution-domainless-publishers). FQDN alignment is NOT required for this identity type. The FQDN mainline — where the cryptographic trust domain MUST align with the authority domain root embedded in the discovery identifier namespace — is otherwise unchanged. + +### 5.1.1 DID-Anchored Identity Resolution (Domainless Publishers) + +When a catalog entry's discovery identifier uses the DID-anchored URN branch ([§4.2.1](#421-agent-identifier-identifier-format-and-rationale)) — or, equivalently, when `trustManifest.identity` is a DID with `identityType: "did"` — registries and orchestrators MUST establish publisher authority by verifying control of the DID rather than by FQDN cross-reference. The procedure is: + +1. **Resolve the DID Document.** Dereference the DID to its DID Document using the method-specific resolution path: + * `did:plc` → `GET https://plc.directory/` + * `did:web` → `GET https:///.well-known/did.json`, where `` is the method-specific identifier. +2. **Select the verification key.** From the DID Document's `verificationMethod` array, select the key indicated by the detached JWS `kid` header parameter when present; otherwise select the first `verificationMethod` whose key type is compatible with the JWS `alg`. +3. **Reconstruct the signed payload.** Canonicalize the signed content using **JCS (JSON Canonicalization Scheme, [RFC 8785](https://www.rfc-editor.org/rfc/rfc8785))**. Canonicalization MUST be JCS and MUST NOT be implementation-defined; JCS is already the canonical form used elsewhere in this specification, keeping a single signing mental model. The detached JWS ([RFC 7515 §A.5](https://www.rfc-editor.org/rfc/rfc7515)) carried in `trustManifest.signature` is computed over these canonical bytes. +4. **Validate the signature.** Verify the detached JWS against the selected verification key. On success, the entry is bound to the DID and the publisher is authoritative for that DID's namespace. On failure, the entry MUST be rejected. + +A successful DID-control proof establishes *who published* the entry; consistent with [§7.2](#72-search-post-search), it MUST NOT be interpreted as a cryptographic trust, compliance, or safety rating for the underlying capability. + ### 5.2 Attestation Object Provides verifiable proof of a claim (e.g., compliance certifications). @@ -696,6 +758,20 @@ Restricting the discovery identifier to this specific URN format, rather than al 4. **Search and Discovery Ergonomics (The @ Resolution Pattern)**: Users and LLMs require intuitive, semantic handles for capabilities (e.g., Assistant@Acme). The structured hierarchy of `urn:air:::` allows search engines and federated registries to parse components deterministically. Registries can easily match natural language queries to the publisher domain (Acme) and the terminal short name (Assistant), enabling high-performance semantic filtering, aggregation, and conflict resolution (e.g., displaying Assistant with a verified Acme shield). 5. **Cross-Network Uniqueness and Federation Scalability**: Domain-anchored URNs guarantee global uniqueness across disparate federated registries without requiring centralized registration databases. Because domain names are already globally unique via the DNS root, anchoring the URN to a domain eliminates collision risks when merging catalogs from multiple upstream registries in auto or referrals federation modes. +### C.1 DID-Anchored Identifiers for Domainless Publishers + +The five properties above assume an FQDN `` root. The DID-anchored branch ([§4.2.1](#421-agent-identifier-identifier-format-and-rationale)) preserves every one of them for publishers that hold no controllable domain: + +1. **Nomenclature stability** — a DID is an immutable logical noun by construction and never encodes a physical network location, so the immutable-noun property is strengthened, not weakened. +2. **Separation of concerns** — the DID remains the searchable discovery handle, while the security principal is the key material resolved from the DID Document ([§5.1.1](#511-did-anchored-identity-resolution-domainless-publishers)). Discovery index and security mesh stay decoupled exactly as in the FQDN branch. +3. **Decentralized trust and authority binding** — DNS is not the only verifiable authority root. Control of a DID is provable without a domain: `did:plc` via its signed PLC operation log, `did:web` via a DNS-anchored `did.json`. Authority is established by the §5.1.1 resolution path in place of an mTLS certificate or SPIFFE SVID issued by the FQDN. Namespace-squatting is foreclosed the same way the FQDN branch forecloses it — an actor cannot present a valid DID-control proof for a DID it does not control. +4. **Search and discovery ergonomics** — the terminal `` and optional `` segments parse identically; only the publisher-root component differs (a DID rather than a domain shield). +5. **Cross-network uniqueness** — DIDs are globally unique by construction, so catalog merges across federated registries remain collision-free without a central registry. + +This branch is deliberately written to compose with the transport-side URN questions raised in [#24 (URN semantics for NAT'd and relay-accessed agents)](https://github.com/ards-project/ard-spec/issues/24): both press the FQDN assumption in item 3 of the main rationale above — #24 from the transport side, this branch from the identity side. A future unified "domainless namespace" amendment should be able to subsume both without conflicting with the wording here. + +**Signing discipline composes with the infrastructure-attestation layer.** The detached JWS in this branch ([§5.1.1](#511-did-anchored-identity-resolution-domainless-publishers)) is computed over JCS-canonicalized ([RFC 8785](https://www.rfc-editor.org/rfc/rfc8785)) bytes — the same canonicalization baseline that SOVP-v1 ([#48](https://github.com/ards-project/ard-spec/pull/48), §5.2.1) pins for its pre-execution attestation payload. The two occupy disjoint section space and impose no normative coupling, but a DID-anchored publisher that also carries a SOVP attestation signs its identity claim and its infrastructure claim under a single canonicalization primitive, preserving one signing mental model across both layers. This is a composition property, not a dependency: neither branch requires the other. + --- ## Appendix D: Formal Schema Definitions