feat: Web Bot Auth (WBA) interop #483
Conversation
Extend the UCP signing-key JWK schema and signature spec to recognize EdDSA (Ed25519) keys per RFC 8037, alongside the existing ECDSA P-256/P-384 support. ECDSA P-256 (ES256) remains the universal UCP baseline. EdDSA is OPTIONAL for general UCP verifiers, with one specific implication: verifiers that opt into Web Bot Auth (WBA) interop MUST support EdDSA because WBA mandates Ed25519. Adding EdDSA as a recognized UCP algorithm is the necessary substrate for that interop path. Why --- UCP today supports ECDSA only. Web Bot Auth standardizes on Ed25519 for HTTP transport identity. UCP signers wanting interop with WBA verifiers cannot do so under an ECDSA-only UCP. This commit makes Ed25519 a recognized UCP algorithm so it can be used; the WBA opt-in story that uses it lands in subsequent commits. This change is purely additive: * ES256 verification remains a MUST (unchanged universal baseline). * ES384 remains OPTIONAL (unchanged). * EdDSA (Ed25519) is added as OPTIONAL for general verifiers; signers MAY use either algorithm and MAY publish keys of either type. * The profile schema's jwk_public_key definition is split into EC and OKP shapes via oneOf, matching standard JWK conventions. Verifier expectations --------------------- * A general UCP verifier MAY implement ES256-only. Existing deployments need not upgrade for this commit's purposes. * A verifier that wants to verify Web Bot Auth-compatible signatures MUST support EdDSA — that's a consequence of opting into WBA, not a UCP-imposed cost. Signer guidance --------------- * For maximum interoperability with UCP verifiers today: use ES256. * For WBA interop: use Ed25519 and coordinate counterparty support, or publish both algorithms and select per request. A merchant participating in both UCP HTTP transport (with WBA interop) and AP2 mandate signing today operates two keys: Ed25519 for HTTP transport, ECDSA P-256 for the AP2 merchant_authorization JWS (which AP2 v0.2 currently requires to be non-deterministic). Both keys live in the same signing_keys[] array and are selected by kid. If AP2 relaxes its algorithm rule in a future revision (tracked in AP2 #268, google-agentic-commerce/AP2#268), the merchant MAY collapse to a single Ed25519 key serving both layers; the wire format does not change. UCP-only sites that do not interact with WBA or AP2 may operate a single ES256 key (the universal baseline) and ignore EdDSA entirely. Schema ------ The jwk_public_key definition uses oneOf to enforce kty/crv consistency: * kty="EC" requires crv in {P-256, P-384} plus x and y coordinates. * kty="OKP" requires crv="Ed25519" plus x (single public key value). Private key material (d, p, q, dp, dq, qi, oth, k) remains explicitly forbidden via the existing "not" guard.
A UCP integrator MAY opt their primary signature into a Web Bot Auth- compatible shape, so the same RFC 9421 signature verifies under both UCP and WBA verifiers with one key and one signing operation. Existing UCP-only signers and verifiers change nothing. What's added ------------ signatures.md gains a new §WBA Interop subsection describing the opt-in: - Algorithm SHOULD be Ed25519 (WBA convention). - Signer MUST emit a Signature-Agent header alongside UCP-Agent. An RFC 8941 Dictionary Structured Field whose member's sf-string is an HTTPS URL pointing to a key directory; the member key matches the Signature-Input signature label. - Signer MUST sign the signature-agent component with ;key="<label>" matching the Signature-Agent member key (RFC 9421 §2.1.2 Dictionary-member component selection). - keyid MUST be the JWK SHA-256 Thumbprint (RFC 7638; RFC 8037 §2 for OKP). - created, expires, tag="web-bot-auth" MUST be in @signature-params. - The data: URI inline JWKS form is out of scope; Signature-Agent MUST carry an HTTPS URL. UCP's existing signed components (ucp-agent, idempotency-key, content-digest, content-type) stay in the signed list — WBA accepts them as "additional components" per the architecture draft §4.2.3. §REST Binding adds: - Signature-Agent header row to the headers table (conditional on WBA opt-in). - signature-agent;key= row to the REST Request Signing components table. - Signature-Agent parsing rules subsection in §REST Request Verification, with the dictionary-member-by-label-match rule. A complete WBA-shape request example shows one Ed25519 signature covering both regimes' required bytes. overview.md §Identity & Authentication picks up a short note about the Signature-Agent header pointing to the signatures.md opt-in. Why --- UCP integrators wanting interop with WBA-conformant verifiers previously needed two keys, two signatures per request, or to skip interop entirely. WBA's architecture draft §4.2.3 explicitly permits additional components beyond the WBA-required set, which makes a single-signature dual-audience shape valid under both regimes. Backwards compatibility ----------------------- Fully additive. UCP-only signers and verifiers continue to operate unchanged. WBA opt-in is per-signature; UCP verifiers built only for UCP-default signatures may need to add RFC 9421 §2.1.2 Dictionary- member component selection support to verify WBA-shape signatures (this is part of being RFC 9421-conformant, not WBA-specific).
Add a top-level keys[] field to the UCP profile schema (RFC 7517 JWK Set), making a UCP profile a valid JSON Web Key Set. This enables one document to serve as both a UCP profile and a Web Bot Auth-compatible key directory at the same URL. Document deployment patterns and the verifier's identity-resolution algorithm. What's added ------------ source/schemas/profile.json: - New top-level keys[] property, sibling to signing_keys[] and ucp. - signing_keys[] stays canonical (every UCP verifier reads it). Description updated to point profiles toward keys[] as the optional JWKS-superset mirror for WBA-directory compatibility. - When both arrays are published, they MUST list the same set of kid values, and entries sharing a kid MUST be semantically equivalent (identical RFC 7638 thumbprints; serialization differences not significant). - EC alg/crv coupling: ES256 with P-256, ES384 with P-384 enforced via if/then in the EC oneOf branch. overview.md: - §Profile Structure: the keys[] mirror, the RFC 7517 §5 "additional members" allowance, and the cross-array equivalence rule. - Business Profile example now publishes both arrays as semantic mirrors, with an Ed25519 key (HTTP transport identity) and an ECDSA P-256 key (AP2 mandate JWT) demonstrating UCP+WBA+AP2 composition. - §Identity & Authentication: tag-driven dispatch language. Sites opting into WBA interop emit both UCP-Agent (capability discovery + default-UCP key lookup) and Signature-Agent (WBA-shape key lookup). - §Key Discovery: regime-aware lookup table (default UCP → signing_keys[]; WBA-shape → keys[]). - New §Deployment Patterns for WBA Interop subsection: Pattern 1 (content negotiation, one URL, two media types); Pattern 2 (two URLs, isolated signing complexity). WBA Response Signing deferred to draft-meunier-http-message-signatures-directory §5.2 with operational guidance on authority-keyed caching. - New §Identity Resolution Algorithm subsection: per-signature dispatch on the tag parameter (tag="web-bot-auth" → resolve via Signature-Agent; no/other tag → resolve via UCP-Agent; unknown tag → skip). Explicit skip semantics for missing Signature-Agent header, fetch failure, non-HTTPS URL, no keyid match, and signed-components mismatch. SHOULD-level keyid↔JWK-thumbprint check for WBA-shape signatures. Authenticated transport-identity rule, with explicit scoping that payload-layer assertions (e.g., AP2 mandate JWTs) follow their own identity binding. signatures.md: - Architecture diagram updated for keys[] / signing_keys[] dual publishing. - §Key Discovery defers publishing contract to overview.md §Profile Structure (regime-aware lookup table only). Backwards compatibility ----------------------- Fully additive. Profiles publishing only signing_keys[] (the canonical field) remain valid. Profiles wanting WBA-directory compatibility add keys[] as a mirror; the two-array dual-publish keeps every existing UCP verifier working unchanged.
|
Hi @igrigorik, Overall this is a strong, well-scoped PR that solves a real problem: a UCP signer couldn't produce a WBA-conformant signature at all before this, and the PR closes that gap without disturbing existing integrators. A few things I think are genuinely well done: the single-signature dual-audience shape (one key, one signing operation, verified by both regimes off the same bytes) is elegant; backward compatibility holds (ES256 stays the universal baseline, keys[] and the WBA opt-in are both optional). I left three inline comments, only one of which I'd treat as a pre-merge discussion:
None of these are objections to the direction, which is right. |
The WBA-interop examples attached kid
"NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs" to the published Ed25519
key, but that value is the RFC 7638 §3.1 thumbprint of the *RSA* example
key. The actual RFC 7638 SHA-256 thumbprint of the published OKP key
{"crv":"Ed25519","kty":"OKP","x":"11qYAY..."} is
"kPrK_qmxVWaYVA9wwBF6Iuo3vVzz7TxHCTwXBygrS4k" (RFC 8037 §A.3).
This matters because the WBA opt-in makes keyid = JWK SHA-256 Thumbprint
a MUST and the identity-resolution algorithm checks it: the example
previously failed its own normative requirement and would mislead anyone
lifting it as a test vector. Replaces all four in-tree occurrences
(signatures.md profile example + wire example; overview.md signing_keys[]
and keys[] mirrors).
The Content-Digest in the HTTP examples used the full RFC 9530 "hello world" digest (X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=), which reads as a real, complete digest but does not hash the body shown in any example. Truncate to X48E9q... so the placeholder is unambiguously illustrative, matching the convention already used by the adjacent Signature lines (MEUCIQD...) and the response example's digest (Y5fK8n...). Display-only: the example validator unwraps HTTP examples to the JSON body before validation, so header values are never parsed. The deterministic, normatively-checked keyid/kid values are intentionally left as real values.
The keys[]/signing_keys[] mirror creates a dual-removal hazard: a key removed from one array but still listed in the other keeps verifying for any verifier reading the stale array. The atomicity rule only mentioned "rotation updates," and the runbook steps said "remove from the profile" without naming both arrays — so the security-critical case (revocation) could fail open.
The PR narrowed the JWK schema's kty/crv/alg into closed enums behind a oneOf, so a single key with an unrecognized type or curve (a future P-521 or post-quantum key) failed validation for the entire signing_keys[]/keys[] array — invalidating the whole profile, including keys a verifier could use. That re-creates the "can't add an algorithm without a breaking schema bump" problem this feature exists to remove, and contradicts the runtime contract (key lookup is by kid, with algorithm_unsupported for keys a verifier cannot use). Replace the closed oneOf with open string vocabularies (kty/crv/alg as examples, not enums) plus allOf if/then conditionals that preserve the real constraints for known types: EC requires crv/x/y, OKP requires crv/x, and P-256/P-384/Ed25519 each couple to their algorithm. Unknown key types now validate (only kid+kty required) instead of bricking the profile. The private-key guard is unchanged. Prose updated for coherence: - signatures.md, overview.md: the kty/crv/alg vocabularies are open and verifiers skip keys they cannot use rather than reject the key set. - Identity-resolution algorithm and REST verify pseudocode now show the algorithm_unsupported path for an unsupported matched key. Verified: ucp-schema lint clean, all doc examples validate, and fixtures confirm known-bad keys (missing y, P-256+ES384, Ed25519+ES256, missing x, private key) are still rejected while unknown types/curves pass.
|
@amithanda ty sir, great catch and feedback on the oneOf. Updated, PTAL. |
|
Rereading the Web Bot Auth Architecture [1] and HTTP Message Signatures Directory [2] drafts, directory discovery is ambiguous. The two specs describe it two different ways with no stated precedence, and it affects whether a profile can double as a key directory.
Concretely, for
Desired stateOne
[1] https://datatracker.ietf.org/doc/html/draft-meunier-web-bot-auth-architecture-05 |
thibmeu
left a comment
There was a problem hiding this comment.
The change looks good overall. I think there is opportunity to align the two specifications
- Add examples for
ecdsa-p256-sha256in web bot auth specification, with an associated implementation - Have a CIMD shape, specifically with jwks_uri. This would allow both WBA and UCP to keep their own namespace ("ucp" and "web-bot-auth"), and have key management to be decorrelated. For WBA, the changes are being proposed thibmeu/http-message-signatures-directory#98
|
[This is a quick review to unblock @igrigorik, largely assisted by claude] OverallThis is a strong, carefully-iterated PR that turns a previously impossible thing — emitting a Web Bot Auth-conformant signature from a UCP signer — into a clean, backward-compatible capability. I'm in favor of the direction, and after the 06-15 fixes the substrate is in good shape. My position is approve after a small set of correctness/interop fixes, with the contested key-publication architecture routed to a tracking issue rather than blocking here. A few things I want to credit specifically (extending @amithanda's top-level praise rather than repeating it):
Security & key lifecycleA3 is resolved in prose — revocation now correctly states a key "is not effectively revoked until it is absent from both arrays" and that add/rotate/remove "MUST update both arrays atomically." Good. The residual I'd put on the record (not re-litigating A3): that MUST is prose-only and structurally unenforceable — Two net-new security items worth resolving before merge: (1) Interop realityThis is the item I'd weight most heavily, and it sharpens @dpeacock's Cloudflare comment and @igrigorik's discovery-precedence question from open-questions into a concrete interop break. I tried to mentally run Pattern 1 (and the worked examples that point Architecture & future-proofingThe central choice — inline Adoption & governanceTwo cheap, high-leverage fixes: the PR description still carries the RSA thumbprint Merge recommendation: approve-after-changes. Land the baseline; gate merge on the cheap correctness/interop items (PR-body thumbprint, |
|
Regarding @pjordan's remarks on interop reality: I do think there is something to address here. Adding something like: Publishing top-level keys[] is necessary but not sufficient for UCP-WBA interop. A profile or directory endpoint used for WBA key discovery MUST be served with per-key HTTP Message Signatures on the response; otherwise WBA verifiers following the directory draft’s recommended validation behavior will ignore the keys. or something to that effect may resolve it. |
Adopt the explicit `type` parameter for Signature-Agent so a verifier no
longer has to guess whether the value is a directory origin or a JWK Set
URL. UCP recommends `type=jwks_uri` pointing at the UCP profile: the
profile's keys[] array is read directly as the JWK Set, so one
/.well-known/ucp document is simultaneously the UCP profile and the WBA
key source — no separate directory, no content negotiation, no directory
media type.
- signatures.md: WBA opt-in step 2, Signature-Agent parsing rules, and
both examples now carry ;type=jwks_uri; post-example prose explains the
single-URL discovery.
- overview.md: Deployment Patterns reframed — Pattern 1 (profile as JWK
Set via jwks_uri, recommended) and Pattern 2 (well-known directory,
fallback for default type=directory verifiers such as Cloudflare
today); WBA Response Signing scoped to the Pattern 2 directory;
identity-resolution algorithm resolves by type.
Tracks the `type` parameter proposed in
draft-meunier-http-message-signatures-directory PR #98
(github.com/thibmeu/http-message-signatures-directory/pull/98), still in
flight; the well-known directory (Pattern 2) remains for interop with
verifiers that have not adopted typed discovery.
…pen thumbprint prose Review nits on PR #483: - Swap the OKP example key to RFC 9421 B.1.4 test-key-ed25519 (x=JrQLj5P..., thumbprint poqkLGiymh...) so UCP examples cross-check directly against Web Bot Auth's own test vectors (architecture A.2) and read as recognizable non-prod material. (thibmeu, pjordan) - Pin all five draft-meunier-* references to -05 (display text + URL); these individual drafts evolve. (thibmeu, pjordan) - Cross-array equivalence MUST now cites the base64url JWK SHA-256 Thumbprint per RFC 7638 Section 3.2 (RSA/EC) and RFC 8037 Appendix A.3 (Ed25519). (thibmeu) - cspell: ignore kid/keyid thumbprint values (opaque base64url, nothing spell-checkable), mirroring the existing x/y JWK-coordinate ignore.
…ed-component gate Two coupled corrections so the verification logic nests correctly and Web Bot Auth stays an optional, additive layer over a self-sufficient base mechanism. 1. Key resolution is verifier-capability-based, not tag-gated. The previous algorithm dispatched on the signature's tag (tag="web-bot-auth" -> Signature-Agent only), which made WBA load-bearing for any tagged signature and left a UCP-only verifier no UCP-Agent path for a dual-audience signature. Now UCP-Agent -> signing_keys[] is the base lookup every UCP verifier supports (untagged or tag="web-bot-auth" signatures); Signature-Agent -> keys[]/jwks_uri is the optional lookup a WBA-aware verifier MAY use. The tag is a hint, not a gate; signatures scoped to another application's purpose are skipped. A dual-audience signature thus verifies for a UCP-only verifier (via UCP-Agent), a WBA-only verifier (via Signature-Agent), or both. Key-list selection follows the resolution mechanism. 2. Covered-component requirements are enforced at the verifier, in every regime and transport. The verifier previously accepted a signature regardless of what it covered, so a signature satisfying only WBA's minimal set (@authority, signature-agent) could authenticate a request whose body/method/path is unbound. Add a presence-based coverage gate: bind the target always, the body when present, and every integrity-relevant header the request carries (ucp-agent, signature-agent, idempotency-key). Presence-based, never branching on HTTP method, so it holds for MCP (all POST) as for REST. Which requests MUST carry Idempotency-Key remains a transport-binding presence rule (REST: method; MCP: operation), separate from coverage. Updated: Identity Resolution Algorithm (resolution, key-list selection, coverage gate), Key Discovery prose (both files), the WBA-opt-in note, both REST verify pseudocode blocks, and the MCP Transport note (Idempotency-Key follows the operation, not the POST). Raised in review on PR #483: WBA must be optional, not required; covered-component gap reported by shopdave; MCP all-POST scoping caught in review.
Two review items (PR #483) on WBA-interop signature semantics: - nonce: the WBA opt-in list omitted the anti-replay nonce. Add it as a SHOULD — base64url, RECOMMENDED 64 bytes, unique within the created/expires window — per draft-meunier-web-bot-auth-architecture-05 §4.2.2, noting that UCP's Idempotency-Key is business-layer payload deduplication, not a transport-bound nonce and not a substitute, and that a verifying origin MAY require a nonce and re-challenge (HTTP 429) per §4.3-4.4. - freshness: the spec both implied RFC 9421 conformance "will enforce" the created/expires window and stated created is OPTIONAL with replay handled at the business layer — a contradiction, and the "will enforce by conformance" was inaccurate. Scope it by regime: default UCP keeps created OPTIONAL with Idempotency-Key replay protection; WBA-shape signatures carry created/expires (required of the signer by WBA §4.2) for WBA verifiers. Enforcing the window is application-defined (RFC 9421 §3.2.1) — not an automatic consequence of conformance and not separately mandated by UCP.
Reframes optional Web Bot Auth (WBA) interop around three pivots, then
closes the correctness/security gaps a review surfaced.
Pivots
------
- UCP does not become a WBA directory. The profile is a valid RFC 7517
JWK Set a signer MAY reuse as its key source; WBA discovery happens via
the Signature-Agent header's type variants (jwks_uri / cimd / directory),
each able to point back at the profile.
- Spec the minimum interop surface; defer mechanics to their source specs.
The in-spec directory self-signature contract ("WBA Response Signing")
and the IRA directory-resolution step are removed — that format, its
per-key self-signatures, and media type belong to the directory draft
(§5.2), not UCP. UCP stops restating RFC 9421 / the WBA drafts / CIMD.
- The three discovery variants are equals. UCP does not rank them; the
right type depends on the counterparty's verifier. The type parameter
is flagged as tracking the unmerged directory-draft PR #98 (may change).
Correctness
-----------
- Define "dual-audience" and require kid == RFC 7638 thumbprint for
dual-audience keys (schema + prose). Otherwise the same signature a WBA
verifier accepts fails UCP-Agent resolution: keyid is the thumbprint and
the UCP verifier matches keyid to a published kid, so both must be it.
- Verifier algorithm: close the covered-component gate to an explicit set
(no open "every integrity-relevant header"); C4 keyid==thumbprint check
SHOULD -> MUST for tag="web-bot-auth"; tighten identity binding (a
Signature-Agent key proves control of that key source, not of the
UCP-Agent profile — treat as one identity only when the URLs match);
note that verifying a dual-audience signature still needs Ed25519 and
RFC 9421 §2.1.2 member selection.
- Fetch safety (the directory draft is silent, so this is UCP's): reject
special-use IPs (RFC 6890) with a loopback carve-out for local dev,
resist DNS rebinding, do not follow in-document URLs to internal
addresses, and bound response size (128 KiB deployment guard — the
schema sets no size limit, so it MUST NOT reject conformant profiles).
Rules apply to every identity-resolution dereference. Cache-refresh on
kid-miss MAY -> SHOULD.
Merges origin/main, resolving the docs/specification/signatures.md conflict with #291 (footnote rendering + MD060 table alignment) by keeping this branch's WBA content and adopting main's backtick-footnote + aligned-table convention. Also carries the WBA-interop alignment and clarity pass below (folded in via amend). Align with merged directory PR #98 ---------------------------------- thibmeu/http-message-signatures-directory#98 merged, confirming our forward-leaning bets: the Signature-Agent `type` parameter (jwks_uri / cimd / directory, default directory) and the §5.2 key-binding contract are now in the directory draft's editor's copy (pending -06; not in published -05). Updated the citation from "PR #98, unmerged, may change" to the draft itself. Verified the architecture-draft §4.2 agent-signature requirements citation still holds. Clarity / de-conflation ----------------------- - The UCP profile is a valid RFC 7517 JWK Set a signer reuses as its key SOURCE — not a "key directory". Reserve "directory" for the WBA well-known mechanism only. Fixed across the profile prose, the Authenticated-identity rule, the signatures heading, the Signature-Agent table cells, the REST verification pseudocode (resolve_signer_key_set), and profile.json. - keys[] -> canonical is "WILL" (not "may"), stated with the valid-JWKS motivation; signing_keys[] is the deprecation target. - Moved the dual-audience example to the top of the WBA Interop section with a coexistence annotation: Signature-Agent is additive alongside UCP-Agent, it does not replace it. - DRY'd the IRA ("tag is a hint, not a gate" stated once); dropped the stale tag argument from the verifier pseudocode; aligned profile.json key descriptions (jwks_uri-scoped verifier note, thumbprint-precise equivalence, signer-scoped EdDSA recommendation).
|
Ty all for thorough feedback. Pushed a major revision, updated PR description to match. Key changes: 1/ UCP doesn't become a WBA directory. 2/ A UCP verifier behaves the same whether or not a signature is WBA-shaped. 3/ "Dual-audience" is now defined and scoped. PR #98 landed – hooray! @thibmeu I filed thibmeu/http-message-signatures-directory#100: would love to remove unnecessary friction here, wdyt? Ready for next review pass — ptal 🙏 p.s. this PR introduces |
The Business Profile example's ECDSA P-256 key used fabricated coordinates. Swap to the RFC 9421 Appendix B.1.3 key (test-key-ecc-p256) so both example keys are recognizable RFC 9421 test keys (the Ed25519 key already is), per reviewer feedback to reuse RFC 9421 test keys for ease of verification.
…ndates
The algorithm/key guidance stated specific prescriptions tied to today's
deployment — Ed25519 for WBA, "two keys" for WBA+AP2 — as if they were
UCP/WBA rules. Generalize to the underlying principle: algorithm choice is
counterparty-driven. The guidance then holds as verifier capabilities (or
AP2's rule) change, without naming a specific algorithm or key count.
signatures.md (§Signature Algorithms)
- Usage guidance is now principle-first: algorithm choice is
counterparty-driven; default to ES256 (the UCP baseline, also WBA-valid);
one key suffices when one algorithm satisfies every audience.
- Ed25519 and the two-key setup demoted to a non-normative observation.
- "WBA verifiers MUST support EdDSA" → SHOULD (soft floor); WBA opt-in item 1
"SHOULD be Ed25519" → "use an algorithm the verifier accepts"; IRA step 1
generalized ("Ed25519" → "whichever algorithm the signer used"); architecture
box de-WBA'd. "Two-key vs one-key" → "Number of signing keys".
- De-duplicate: the RFC 9421 HSA registry list now appears once (WBA opt-in);
drop the redundant "does not mandate a specific one" and the "Cloudflare"
vendor name.
ap2-mandates.md (§Cryptographic Requirements) — now the home for AP2 algorithm detail
- The AP2 bullet in §Signature Algorithms is now a pointer here.
- Defer the algorithm to AP2's rule (AP2 v0.2 requires ECDSA) and add a Note
covering the entropy basis (UCP's per-session Checkout id supplies it), AP2
v0.2's specification.md-vs-S&P contradiction, AP2 #268, and that under the
entropy reading one key (incl. Ed25519) serves both AP2 and WBA.
- Reconcile the alg field table and verify pseudocode to defer rather than
hard-code ES256/ES384/ES512.
overview.md
- IRA step 1 generalized; business-profile caption defers the one-vs-two-key
rule to §Signature Algorithms (no longer cites AP2's non-deterministic rule).
thibmeu
left a comment
There was a problem hiding this comment.
The changes to the specification make it much closer to WBA, specifically with the optional keys.
The addition of Signature-Agent with directory/jwks_uri/cimd helps a lot, and reuses discovery via signatures components.
Only question mark I'd have is regarding using keys rather than jwks_uri, but that's a recommendation that can evolve later, and that's valid today
| selects how a verifier resolves the advertised keys. (The `type` | ||
| parameter and its `jwks_uri`/`cimd`/`directory` values were added via | ||
| [directory-draft PR #98](https://github.com/thibmeu/http-message-signatures-directory/pull/98); | ||
| they are in the editor's copy, pending publication as -06.) Each |
There was a problem hiding this comment.
@thibmeu that's an item on me. Should be this week
|
[Second pass, post the 06-19 revision. Largely assisted by Claude, with the external claims checked against primary sources by Claude.] I am approve ready. Claude's reviewThe 06-19 revision is a big step and it resolved most of what I — and @amithanda, @shopdave, @thibmeu — raised last round. Crediting the changes specifically so we don't re-litigate them: One thing I checked that turned out fine: the |
|
@thibmeu ty for your help and feedback! @pjordan clarification on That aside, I believe this is good land. Ready for final pass. |
Co-authored-by: Thibault <thibault@cloudflare.com>
Point the Signature-Agent `type` parameter at draft-meunier §4.1 (to be published in -06) via the IETF datatracker htmlized draft, replacing the now-merged/closed PR #98 link and the github.io editor's-copy link. Reflow thibmeu's tag-skip sentence to the file's line-wrap width.
1afd0b1 to
15e6c77
Compare
shopdave
left a comment
There was a problem hiding this comment.
LGTM with minor corrections.
|
Hi @igrigorik, +1 to addressing @shopdave's suggestions few hours ago. I wanted to flag a concern regarding the normative coupling to the unreleased The Concern: Spec Drift & Out-of-Date ReferencesIn
Suggestion: I completely appreciate the goal to keep UCP isolated from WBA directory internals. However, to protect early implementers from spec drift before the final RFC lands, could we either temporarily point the Markdown links directly to a commit-locked version of the editor's copy where they are defined, or add a brief informative footnote indicating that these parameters track the upcoming Single-Array MigrationThe security gaps @shopdave highlighted in the |
Co-authored-by: David Pettersson <david.pettersson@shopify.com>
thibmeu
left a comment
There was a problem hiding this comment.
the latest editor copy of the webobotauth drafts have been published on the datatracker. there has been name changes (based on feedback from the wg), which i've added here, in addition to pinning the versions
- REST verify pseudocode now consistently skip-and-try-next: remaining
hard error(...) returns (request digest; all of verify_rest_response)
become skip_signature(...), plus a note that each routine verifies a
single candidate — authenticated iff one verifies, rejected only when
every candidate skips (RFC 9421 §4.3 / IRA).
- overview: caveat that a WBA verifier reads keys[] only via
type=jwks_uri/cimd; default type=directory expects a signed directory,
not a static profile.
- signatures: add "interop is directional" callout (UCP verifier ⊂ WBA).
- cspell: dedup custom-words.txt.
The WBA drafts were renamed/re-adopted:
http-message-signatures-directory -> webbotauth-httpsig-directory
web-bot-auth-architecture -> webbotauth-httpsig-protocol
Update all citations to the new slugs and pin -00 — the published
version that now carries the Signature-Agent `type` parameter at §4.1,
resolving the "params not in published draft" concern. Fix section
numbers that shifted in the protocol draft: nonce §4.2.2 -> §4.2.3,
additional components §4.2.3 -> §4.2.4 (§4.2 unchanged). Keep the
well-known path and media type, which the new draft retains.
|
@thibmeu ty, landed updates with a few additional section pointer fixes. @amithanda prescient comments! The Re, single-array migration: 👍 and I'll stage that as soon as we land this. |
UCP specifies RFC 9421 message signatures, but had incompatible restrictions and missing guidance for interoperating with Web Bot Auth (WBA):
signing_keys[]; WBA verifiers read an RFC 7517keys[]JWK Set. UCP neither forbadekeys[]nor defined its role.UCP-Agentpoints at the UCP profile;Signature-Agentadvertises WBA keys. UCP didn't define how a verifier picks between them.This PR resolves all three with a single-signature, dual-audience shape: one key, one signing operation, one signature on the wire that both a UCP verifier (via
UCP-Agent) and a WBA verifier (viaSignature-Agent) accept. WBA's protocol draft §4.2.4 permits additional covered components, which makes this valid under both regimes once the algorithm is supported and header roles are defined.What this PR does
Open algorithm vocabulary. The JWK schema validates EC and OKP via
if/then(openkty/crv/alg; unknown keys are tolerated, never whole-profile-rejected).ES256stays the universal MUST baseline;EdDSA(Ed25519) is OPTIONAL for general verifiers and MUST for verifiers that support WBA.Profile as a JWK Set. The profile gains an optional top-level
keys[](RFC 7517) mirroring canonicalsigning_keys[]; when both are present they MUST list the samekids with semantically equivalent JWKs (identical RFC 7638 thumbprints). RFC 7517 §5 permits the extra members, so the document is simultaneously a UCP profile and a valid JWK Set — a signer MAY reuse it as its WBA key source. (keys[]is published as an interim step toward promoting it to canonical and deprecatingsigning_keys[]in a future UCP version — separate PR.)"Dual-audience" defined, with scoped requirements. A dual-audience signature carries
tag="web-bot-auth", signs thesignature-agentcomponent, setskeyidto the key's RFC 7638 thumbprint, and includescreated/expires(nonce SHOULD). For such keys the publishedkidMUST equal the thumbprint, so the WBA lookup (by thumbprint) and the UCP lookup (keyid→kid) resolve the same key. WBA interop is request-scoped; responses use standard UCP signatures.Discovery: three equal
Signature-Agentvariants.type=jwks_uri(a JWK Set URL — point it at the profile),type=cimd(a Client ID Metadata Document whosejwks_urimay point back at the profile),type=directory(an origin hosting a well-known directory). UCP does not rank them — the right choice depends on the counterparty's verifier. Thetypeparameter and its values are defined indraft-meunier-webbotauth-httpsig-directory-00§4.1 (the renamed/re-adopted directory draft, formerlydraft-meunier-http-message-signatures-directory). The directory's format, per-key self-signatures, and media type are deferred to the same draft §5.2 — UCP does not restate them.Verifier (Identity Resolution Algorithm): capability-based, not tag-gated. The
tagis a hint, not a gate. A UCP verifier always resolves viaUCP-Agent(so a UCP-only verifier never implements WBA discovery — it only needs Ed25519 + RFC 9421 §2.1.2 to verify the bytes); a WBA-aware verifier MAY additionally resolve viaSignature-Agent. A closed, explicit covered-component gate is enforced in every regime, so a WBA-minimal signature can never authenticate a UCP request whose body/method/path/headers are unbound.keyid==thumbprint is MUST for WBA-shape signatures. Identity is the URL that supplied the verifying key; aSignature-Agentkey is treated as the same identity asUCP-Agentonly when the URLs match.Fetch safety. UCP specifies it for every identity-resolution dereference (profile,
jwks_uri, CIMD), aligned with the WBA protocol draft's SSRF guidance: reject special-use IPs (RFC 6890) with a loopback carve-out for local dev, resist DNS rebinding, don't follow in-document URLs to internal addresses, and bound response size (a deployment guard — the schema sets no size limit).On the wire
Default UCP signature (unchanged)
Dual-audience opt-in signature (new)
One signature on the wire. UCP verifiers route via
UCP-Agent; WBA verifiers route viaSignature-Agent. Both verify the same bytes against the same key, and both headers can point at the same/.well-known/ucpURL (orSignature-Agentcan point elsewhere).Backwards compatibility
signing_keys[]remain valid;keys[]is OPTIONAL.UCP-Agent.Future direction
A UCP+AP2+WBA merchant operates two keys today (Ed25519 for HTTP/WBA, ECDSA P-256 for AP2
merchant_authorization, per AP2 v0.2). Two upstream moves collapse this to one: (1) AP2 #268 relaxing the non-deterministic-signature requirement, and (2) UCP promotingkeys[]to canonical. The wire format and verifier algorithm here already point at that future.Routed to a follow-up tracking issue (not expanded here): promoting
keys[]/jwks_uri/CIMD convergence + migration, andtagnamespace reservation.Checklist