Skip to content

Object signature base for signed body objects (Consumer Recognition Object / Payment Container) is under-specified — request for a worked example or test vector #23

Description

@AVAVERIFY

Context

We've built an independent merchant-side TAP verifier (AVA Pay) implementing all three layers to public-spec depth: the RFC 9421 message signature (agent-browser-auth / agent-payer-auth tags, ed25519 + rsa-pss-sha256), Consumer Recognition Object validation including the Visa-signed PS256 IdToken verified against the production JWKS at mcp.visa.com/.well-known/jwks, and Agentic Payment Container validation. Wire format is locked to this repo's sample messages, and our test suite runs real cryptography for every layer.

One construct blocked exact interoperability: the object signature base for the signed body objects.

The gap

For the object-level signatures (Consumer Recognition Object, Agentic Payment Container), the public spec's guidance is a single sentence — the base is "a canonical representation of all fields in the object in the order received", excluding the signature field. There is no worked example, no test vector, and no definition of "canonical representation" in either the developer.visa.com pages or this repository's samples (the samples show signed objects, but not the exact byte string that was signed).

That leaves an independent implementer to guess at least four things:

  1. Rendering — is each field rendered as raw JSON, a "name": value line, or something else? Are string values quoted or raw?
  2. Nested values — compact JSON? Key order preserved? Whitespace rules?
  3. Joining — line separator (\n? none? CRLF?), trailing separator or not?
  4. Field order — "order received" presumably means JSON insertion order, but that's worth confirming since some stacks don't preserve it.

Any two reasonable-but-different answers produce signers and verifiers that cannot interoperate, while each passes its own round-trip tests — the failure mode is silent until two independent implementations meet.

Our documented interpretation

Mirroring the RFC 9421 message-signature base style: one "name": value line per field in object insertion order, string values raw, non-string values as compact JSON, lines joined with \n, signature excluded. Implementation (signer and verifier share it):

https://github.com/AVA-PAY/ava-pay/blob/main/packages/agent-sdk/src/protocol/visa-tap/index.ts (buildTapObjectSignatureBase)

Ask

  1. A normative worked example in this repo: one sample Consumer Recognition Object plus the exact signature base string and signature for a published test key — that single artifact resolves all four ambiguities at once.
  2. Failing that, a sentence in the spec defining the rendering/joining/ordering rules.

If our interpretation matches Visa's intent, we're happy to contribute a PR adding test vectors (we already generate them in CI). If it doesn't, we'll change our implementation to match — one function, by design.

Thanks — the three-layer design is clean to implement against, and production-verifiable IdTokens via the public JWKS made independent validation possible. This is the one place we had to interpret rather than follow.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions