Signing and identity
A signed manifest is the difference between 'someone parked some JSON at a URL' and 'the legal entity that owns this domain authored this manifest'. The signature envelope is a detached JWS over the canonicalised manifest body. The strongest signing primitive is a vLEI role credential, but the spec supports self-signed and DNS-pinned alternatives.
Why sign
The threat model BCP signing addresses.
| Without signature | With signature |
|---|---|
| Anyone who can write to the well-known path can publish a manifest claiming any commerce primitives, MCP endpoints, allow-actions, etc. | Only the holder of the signing private key can mint a valid manifest. Compromise of the web server alone is insufficient. |
| A man-in-the-middle on the CDN edge could rewrite the manifest before it reaches the consumer. | The consumer verifies the signature on its end after fetching. Edge rewrites are detected. |
| No proof that the legal entity in identity.legalName is the same party as the manifest publisher. | vLEI binding cryptographically chains the signing key to a GLEIF Level-1 LEI record. |
| No proof against the manifest being replayed from a stale snapshot. | signedAt plus bcp:expires plus the manifest's bcp:updated timestamp together give monotonic freshness. |
vLEI primer
Verifiable Legal Entity Identifier. The strongest signing primitive.
The vLEI standard (ISO 17442-3, published 2024) issues cryptographic credentials that bind a legal entity to a signing key, anchored in the GLEIF root of trust. Issuance happens through accredited Qualified vLEI Issuers (QVIs). The credential format is W3C Verifiable Credentials over KERI. ISO 5009 role codes (OOR) extend the model with credentials issued to individuals acting on behalf of an entity (CEO, CFO, authorised signatory).
For BCP, the vLEI gives us two things: a verifiable chain from the signing key to the LEI in the manifest's identity block, and a documented mechanism for credential revocation via GLEIF's witness mesh.
- Standard
- GLEIF vLEI
- Format
- W3C Verifiable Credentials, KERI key event log, signed by accredited QVI.
- Algorithms
- Ed25519 native, ES256 supported.
- Issuance cost
- USD 100-500 / year via accredited QVI. Verification is free.
- Active credentials (Q1 2026)
- 3.02M live LEIs, single-digit-thousands vLEIs. Adoption still early.
- Revocation
- KERI key event log entries. Witnesses publish revocations to GLEIF mesh.
Signature envelope
The JWS shape and how it sits inside the manifest.
Top-level block
kid resolution table
| kid prefix | Resolves to | Trust level |
|---|---|---|
| vlei:<LEI>:ofcr:<role>:<period> | GLEIF KERI witness mesh resolves the role credential. | L3 |
| dnskey:<domain>:<fp> | Public key whose fingerprint matches DNS TXT _bcp.<domain> | L2 |
| selfsigned:<fp> | Public key embedded in the manifest's identity.publicKey field. | L1 |
| x5u:<url> | Certificate chain fetched from the x5u URL. | L2 / L3 depending on chain trust anchor |
JWS value
The value field is a JWS in detached-payload form. The protected header is included; the payload is empty (the canonicalised manifest body is the implicit payload). This shape is RFC 7797 (JWS Unencoded Payload Option) with the payload omitted from the wire format.
Canonicalisation
JCS over the manifest body. The signature block is excluded.
JSON Canonicalization Scheme (JCS, RFC 8785) gives the manifest body a deterministic byte representation. Both the signer and the verifier must arrive at the same byte string regardless of indentation, key order, or whitespace differences.
- 01Take the manifest bodyThe full JSON object as stored or transmitted.
- 02Remove the signature blockDelete the top-level
signatureproperty if present. - 03Apply JCSRecursively sort keys lexicographically, normalise numbers per ECMAScript JSON.stringify, escape strings per RFC 8259, no insignificant whitespace.
- 04Hash and signSHA-256 the JCS output for ES256. Sign with the private key. The base64url-encoded signature becomes the
value. - 05Insert signature blockAdd the
signatureback to the manifest with the freshly-computed value, alg, kid, and signedAt.
Key rotation
How to rotate signing keys without breaking consumers.
- 01Announce the next keyAdd a
next-keytag to the DNS TXT record with the fingerprint of the upcoming key. Wait at least 24 hours (one TTL cycle) before the swap. - 02Mint a transitional manifestRe-sign the manifest with the current key but include both fingerprints in DNS. Consumers that read DNS during this window will pre-trust the next key.
- 03SwapReplace the
keytag with the new fingerprint. Re-sign all subsequent manifests with the new key. - 04Keep next-key as old-key for revocation graceOnce the swap completes, the previous key fingerprint remains in DNS as
old-keyfor 7 days so any cached manifest signed by the old key still verifies until consumers re-fetch.
Fallback without vLEI
What to do when the publisher has no vLEI credential.
vLEI is not free and not universally adopted. The spec supports two fallbacks that still produce verifiable manifests at L1 or L2, without requiring a vLEI.
DNS-pinned self-signed key (L2)
The publisher generates an Ed25519 or P-256 key pair, publishes the fingerprint in_bcp.<domain> TXT, and signs manifests with the private key. Trust derives from control of the DNS zone. Most Ultron customers will be here.
X.509 chain (L2 or L3 depending on root)
The publisher signs with a key whose certificate chain is reachable via x5u. Useful for entities that already have an enterprise PKI, do not yet have a vLEI, but want machine-verifiable trust without standing up a new DNS workflow.
Verification flow
Consumer-side: how to verify a signature.
- 01Parse the signature blockExtract alg, kid, signedAt, value. Reject the manifest if any are missing.
- 02Resolve the public keyUse the kid prefix to dispatch:
vlei:→ query GLEIF,dnskey:→ DNS TXT,selfsigned:→ identity.publicKey,x5u:→ fetch chain. - 03Canonicalise the bodyRemove the signature block, apply JCS, compute the signature input.
- 04Verify the JWSRun JOSE verification with the resolved public key. Reject on failure.
- 05Check freshnessConfirm signedAt is within an acceptable skew (default ±300s) and bcp:expires has not passed.
- 06Assign trust levelBased on the kid prefix and DNS-binding state, assign L0-L3. Surface this to the calling agent.
Agent-issued credentials
Open question: how does an agent-formed entity sign its own manifest?
autonomous primitive once GLEIF or FIDO ship a credential format for it.For now, autonomous entities should sign at L1 with a self-signed key, declareidentity.autonomous: true as a vendor extension, and rely on operational reputation rather than chained identity. We expect to revisit this within a year as the underlying credential standards mature.