fido4vc-jcs-2026 Cryptosuite
This page is the normative specification for the fido4vc-jcs-2026 cryptosuite. Implementers should be able to produce interoperable signers and verifiers from this page alone.
Overview
Section titled “Overview”fido4vc-jcs-2026 is a W3C VC Data Integrity cryptosuite. It maps a FIDO2 / WebAuthn assertion produced by an external authenticator into a DataIntegrityProof value attached to a Verifiable Presentation (or, in principle, any signed JSON-LD document).
Verify-only by design. Signing is performed outside a cryptosuite library — by a FIDO authenticator over a WebAuthn ceremony. The cryptosuite specifies how to construct the WebAuthn challenge from the document so the resulting assertion can be embedded as a proof and later verified.
Identifiers
Section titled “Identifiers”| Property | Value |
|---|---|
| Cryptosuite name | fido4vc-jcs-2026 |
| Proof type | DataIntegrityProof |
| Canonicalization | JSON Canonicalization Scheme (RFC 8785) |
| Hash algorithm | SHA-256 (FIPS 180-4) |
| Signature algorithm | ECDSA over P-256 with SHA-256 (ES256, FIPS 186-5, RFC 7518 §3.4) |
| Signing mechanism | WebAuthn navigator.credentials.get() ceremony |
| Verification method type | JsonWebKey with kty: "EC", crv: "P-256" |
| DID methods | Any DID method whose resolution yields a conforming JsonWebKey (tested with did:jwk, did:key, did:web) |
The cryptosuite name follows the W3C VC-DI naming convention <base>-<canonicalization>-<year>: fido4vc identifies the underlying signing mechanism family, jcs identifies the canonicalization, 2026 is the year of registration.
Conformance requirements
Section titled “Conformance requirements”Implementations conforming to this specification MUST:
- Use RFC 8785 (JCS) for canonicalization. Implementations SHOULD use Erdtman’s reference implementation (
canonicalizeon npm,io.github.erdtman:java-json-canonicalizationon Maven Central) to ensure bit-identical canonicalization across language bindings. - Use SHA-256 for all hashing operations.
- Recognize
proofValueas a multibase-encoded string (prefixu, base64url without padding per RFC 4648 §5) whose decoded payload is a CBOR-encoded (RFC 8949) 3-element byte-string array[authenticatorData, signature, clientDataJSON], in that fixed field order. - Validate the WebAuthn challenge binding before checking the signature.
- Dereference
proof.verificationMethodper VC-DI §4 — Retrieve Verification Method and CID 1.0 §3.3 to aJsonWebKeywhosepublicKeyJwkhaskty: "EC"andcrv: "P-256". The cryptosuite is DID-method-agnostic; any URL whose dereferencing yields such a key MAY be used (e.g.,did:jwk,did:key,did:web). - Set
proof.proofPurposeto"authentication". WebAuthn is fundamentally an authentication primitive; verifiers MUST reject proofs whoseproofPurposehas any other value.
Implementations MAY:
- Support additional EC curves beyond P-256 (e.g., P-384) via extension. Such implementations MUST register a distinct cryptosuite name.
- Support attested authenticators (validate
attestationObjectchain). The base spec leaves attestation out-of-scope.
Credential registration
Section titled “Credential registration”This cryptosuite specifies how to verify WebAuthn assertions; it does not perform credential creation. Before Proof Serialization can run, a WebAuthn credential MUST already exist on the user’s authenticator. The credential is created out-of-band, prior to any signing ceremony, via the WebAuthn navigator.credentials.create() ceremony.
To ensure the resulting assertions are verifiable under fido4vc-jcs-2026, the registration ceremony MUST constrain the credential to this cryptosuite’s signature algorithm. The PublicKeyCredentialCreationOptions.pubKeyCredParams array MUST contain at least one entry whose:
typeis"public-key";algis-7(the COSE Algorithm identifier for ES256, i.e. ECDSA with SHA-256 over P-256, defined in RFC 7518 §3.4).
The array SHOULD NOT contain entries for algorithms unsupported by this cryptosuite (e.g., -257 RS256, -8 EdDSA). If the authenticator selects an unsupported algorithm during credential creation, the resulting assertions will not verify and the credential will be unusable for fido4vc-jcs-2026.
Other aspects of credential creation — RP/user identifier provisioning, attestation conveyance, resident-key requirements, authenticator-selection criteria — are WebAuthn-layer concerns and out of scope of this cryptosuite. See W3C WebAuthn Level 3 §5.1.3 for the full registration ceremony specification.
Instantiate Cryptosuite
Section titled “Instantiate Cryptosuite”This algorithm configures the fido4vc-jcs-2026 cryptographic suite to be used by the Add Proof and Verify Proof functions of Verifiable Credential Data Integrity 1.0. The algorithm takes an options object (map options) as input and returns a cryptosuite instance (struct cryptosuite).
- Initialize
cryptosuiteto an empty struct. - If
options.typedoes not equalDataIntegrityProof, returncryptosuite. - If
options.cryptosuiteequalsfido4vc-jcs-2026, then:- Set
cryptosuite.createProofto the algorithm in § Create Proof (fido4vc-jcs-2026). - Set
cryptosuite.verifyProofto the algorithm in § Verify Proof (fido4vc-jcs-2026).
- Set
- Return
cryptosuite.
Algorithms
Section titled “Algorithms”This cryptosuite uses JSON Canonicalization Scheme (JCS, RFC 8785) for canonicalization, SHA-256 for hashing, and ECDSA over P-256 with SHA-256 (ES256) executed inside a FIDO2/WebAuthn authenticator for signature production. The proof value packages the WebAuthn assertion (authenticatorData, signature, clientDataJSON) into a deterministic CBOR blob (RFC 8949 §4.2) encoded as a multibase base64url string (prefix u), conforming to W3C VC-DI §2.1.
Transformation (fido4vc-jcs-2026)
Section titled “Transformation (fido4vc-jcs-2026)”The following algorithm specifies how to transform an unsecured input document into a transformed document ready to be provided as input to the hashing algorithm.
Required inputs are an unsecured data document (map unsecuredDocument) and transformation options (map options). The transformation options MUST contain a type identifier (type) for the cryptographic suite and a cryptosuite identifier (cryptosuite). A transformed data document (byte sequence) is produced as output. Whenever this algorithm encodes strings, it MUST use UTF-8 encoding.
- If
options.typeis notDataIntegrityProoforoptions.cryptosuiteis notfido4vc-jcs-2026, an error MUST be raised and SHOULD convey an error type ofPROOF_TRANSFORMATION_ERROR. - Let
transformedDocumentbe the result of applying RFC 8785 (JCS) canonicalization tounsecuredDocument, producing a UTF-8 byte sequence. - Return
transformedDocumentas the transformed data document.
Hashing (fido4vc-jcs-2026)
Section titled “Hashing (fido4vc-jcs-2026)”The following algorithm specifies how to cryptographically hash a transformed data document and a canonical proof configuration into a hash value ready to be provided as input to the proof serialization or proof verification algorithms.
Required inputs are a transformed data document (byte sequence transformedDocument) and a canonical proof configuration (byte sequence canonicalProofConfig). A single hash value (byte sequence hashData) is produced as output.
- Let
combinedBytesbe the concatenationtransformedDocument ‖ canonicalProofConfig. - Let
hashDatabe the result of applying SHA-256 tocombinedBytes. - Return
hashDataas the hash data.
Proof Configuration (fido4vc-jcs-2026)
Section titled “Proof Configuration (fido4vc-jcs-2026)”The following algorithm specifies how to generate a canonical proof configuration from a set of proof options. The output is used as input to the hashing algorithm.
Required inputs are proof options (map options) and the unsecured data document (map unsecuredDocument). The proof options MUST contain a type identifier (type) and a cryptosuite identifier (cryptosuite). A canonical proof configuration (byte sequence) is produced as output.
- Let
proofConfigbe a clone ofoptions. - If
proofConfig.typeis notDataIntegrityProoforproofConfig.cryptosuiteis notfido4vc-jcs-2026, an error MUST be raised and SHOULD convey an error type ofPROOF_GENERATION_ERROR. - If
proofConfig.createdis set and the value is not a valid [[XMLSCHEMA11-2]] datetime, an error MUST be raised and SHOULD convey an error type ofPROOF_GENERATION_ERROR. - Remove the
proofValueproperty fromproofConfig, if present. - Set
proofConfig.@contexttounsecuredDocument.@context. - Let
canonicalProofConfigbe the result of applying RFC 8785 (JCS) canonicalization toproofConfig. - Return
canonicalProofConfig.
Proof Serialization (fido4vc-jcs-2026)
Section titled “Proof Serialization (fido4vc-jcs-2026)”The following algorithm specifies how to derive a proof value from hash data. The cryptographic signing operation is performed by a FIDO2/WebAuthn authenticator external to the cryptosuite library; the library prepares the WebAuthn challenge from hashData and packages the authenticator’s response into the proof value.
Required inputs are a hash value (byte sequence hashData) and proof options (map options). A proof value (string proofValue) is produced as output.
- Invoke a WebAuthn
navigator.credentials.get()ceremony withPublicKeyCredentialRequestOptionscontaining:challengeset tohashData;- the relying party identifier (
rpId); - the user’s
allowCredentials; userVerificationset to"required".
- Let
assertionbe the resultingAuthenticatorAssertionResponse, containing:authenticatorData(byte sequence) — the WebAuthn authenticator data structure;clientDataJSON(byte sequence) — the UTF-8 JSON encoding of CollectedClientData, which MUST include achallengefield whose value equals the base64url encoding ofchallengeBytes;signature(byte sequence) — DER-encoded ECDSA-P256-SHA-256 signature overauthenticatorData ‖ SHA-256(clientDataJSON).
- Let
proofBytesbe the deterministic CBOR encoding (RFC 8949 §4.2) of the 3-element byte-string array[authenticatorData, signature, clientDataJSON], in that fixed order. - Let
proofValuebe the multibase encoding ofproofBytesusing prefixu(base64url without padding, RFC 4648 §5). - Return
proofValue.
Create Proof (fido4vc-jcs-2026)
Section titled “Create Proof (fido4vc-jcs-2026)”The following algorithm specifies how to create a data integrity proof given an unsecured data document.
Required inputs are an unsecured data document (map unsecuredDocument) and a set of proof options (map options). A data integrity proof (map proof), or an error, is produced as output.
- Let
proofbe a clone ofoptions. - Let
canonicalProofConfigbe the result of running the Proof Configuration algorithm withoptionsandunsecuredDocumentpassed as parameters. - Let
transformedDatabe the result of running the Transformation algorithm withunsecuredDocumentandoptionspassed as parameters. - Let
hashDatabe the result of running the Hashing algorithm withtransformedDataandcanonicalProofConfigpassed as parameters. - Let
proofValuebe the result of running the Proof Serialization algorithm withhashDataandoptionspassed as parameters. - Set
proof.proofValuetoproofValue. - Return
proofas the data integrity proof.
Verify Proof (fido4vc-jcs-2026)
Section titled “Verify Proof (fido4vc-jcs-2026)”The following algorithm specifies how to verify a data integrity proof given a secured data document.
Required input is a secured data document (map securedDocument). The algorithm returns a verification result, a struct whose items are:
verified—trueorfalseverifiedDocument—Nullifverifiedisfalse; otherwise an unsecured data document
When a step below says “an error MUST be raised”, the algorithm MUST return a verification result with verified set to false and verifiedDocument set to Null, and SHOULD convey the specified error type.
- Let
unsecuredDocumentbe a copy ofsecuredDocumentwith theproofproperty removed. - Let
proofbe the value ofsecuredDocument.proof. - Validate proof purpose. If
proof.proofPurposeis not equal to"authentication", an error MUST be raised and SHOULD convey an error type ofPROOF_VERIFICATION_ERROR. (This cryptosuite is bound to the WebAuthn authentication primitive; other proof purposes such asassertionMethodare not supported.) - Decode proof value.
- If
proof.proofValueis not a string beginning with the multibase prefixu, an error MUST be raised and SHOULD convey an error type ofPROOF_VERIFICATION_ERROR. - Strip the leading
u; base64url-decode the remaining characters to obtainproofBytes. - CBOR-decode
proofBytesas a 3-element byte-string array[authenticatorData, signature, clientDataJSON]. If the structure does not match, an error MUST be raised and SHOULD convey an error type ofPROOF_VERIFICATION_ERROR.
- If
- Let
optionsbe a clone ofproofwith theproofValueproperty removed. - Let
canonicalProofConfigbe the result of running the Proof Configuration algorithm withoptionsandunsecuredDocumentpassed as parameters. - Let
transformedDatabe the result of running the Transformation algorithm withunsecuredDocumentandoptionspassed as parameters. - Let
hashDatabe the result of running the Hashing algorithm withtransformedDataandcanonicalProofConfigpassed as parameters. - Parse clientDataJSON. Interpret
clientDataJSONas a UTF-8 JSON object. If parsing fails, an error MUST be raised and SHOULD convey an error type ofPROOF_VERIFICATION_ERROR. - Validate WebAuthn assertion type. If
clientDataJSON.typeis not equal to"webauthn.get", an error MUST be raised and SHOULD convey an error type ofPROOF_VERIFICATION_ERROR. (This prevents confusion attacks where a registration-ceremony assertion is substituted for an authentication assertion.) - Bind challenge. If
clientDataJSON.challengedoes not equal the base64url encoding ofhashData, an error MUST be raised and SHOULD convey an error type ofINVALID_CHALLENGE_ERROR. - Retrieve verification method. Let
publicKeybe the public key associated withproof.verificationMethod, retrieved as described in VC-DI §4 — Retrieve Verification Method and CID 1.0 §3.3. The dereferenced object MUST contain atypeofJsonWebKeywhosepublicKeyJwkhaskty: "EC"andcrv: "P-256"; otherwise an error MUST be raised and SHOULD convey an error type ofPROOF_VERIFICATION_ERROR. - Verify signature. Let
signedBytesbeauthenticatorData ‖ SHA-256(clientDataJSON). Verify the ECDSAsignatureagainstpublicKeyoversignedBytesusing ES256. If verification fails, an error MUST be raised and SHOULD convey an error type ofPROOF_VERIFICATION_ERROR. - Return a verification result with
verifiedset totrueandverifiedDocumentset tounsecuredDocument.
Notes for implementers
Section titled “Notes for implementers”- DER vs. raw ECDSA. WebAuthn authenticators emit DER-encoded ECDSA signatures (ASN.1 SEQUENCE of two INTEGERs). Java’s
Signature.getInstance("SHA256withECDSA")accepts DER directly. Node’s WebCryptosubtle.verifyrequires rawr ‖ sand needs an unwrap step. clientDataJSONparsing. Be defensive about whitespace and field order inclientDataJSON. Per the WebAuthn spec, the authenticator produces a specific format, but extension fields may appear; onlychallengeis relied on by this cryptosuite.- WebAuthn ceremony validation is out of scope of this cryptosuite. Validation of
rpId,clientDataJSON.origin, theauthenticatorDataflags (UV, AT, BE, BS), signature-counter monotonicity, and attestation chain are WebAuthn-layer concerns, not cryptosuite concerns. Verifiers operating inside a full WebAuthn ceremony context SHOULD perform the additional checks described in W3C WebAuthn Level 3 §7.2. The cryptosuite makes one exception:clientDataJSON.typeMUST equal"webauthn.get"(enforced in the Verify Proof algorithm) because the check is cheap and prevents a well-known confusion-attack class. proof.challengeandproof.domain. When present inoptions, these fields are folded into the canonical proof configuration by the Proof Configuration algorithm and therefore become cryptographically bound to the signature viahashData. The WebAuthnchallengeishashDataitself, not a separate verifier-supplied nonce.
Test vectors
Section titled “Test vectors”A small reference fixture is included with the TypeScript reference implementation: tests/fido4vc.test.ts. It captures a single end-to-end WebAuthn ceremony from the reference deployment — the holder DID-JWK, the WebAuthn assertion (authenticatorData, clientData, signature), and the full signed VP.
Security considerations
Section titled “Security considerations”Cross-implementation determinism. The most likely interoperability hazard is non-RFC-8785-compliant JCS implementations. Implementers SHOULD use the Erdtman references on each platform. Subtle differences in number formatting (notably exponent handling) or escape sequences will silently produce mismatched hashes.
Replay protection. Replay protection is not provided by the cryptosuite. The verifier supplies a challenge in the proof options; replay is prevented by the verifier rejecting reused challenge values. If the verifier doesn’t track challenges, replay is possible.
WebAuthn ceremony validation. A standalone cryptosuite verifier doesn’t have access to the full WebAuthn ceremony context (origin, rpId, attestation chain). Verifiers wanting strict WebAuthn-grade assurance SHOULD add ceremony-level checks on top of cryptosuite verification.
Key compromise. If a user’s FIDO authenticator is compromised, the attacker can produce valid fido4vc-jcs-2026 signatures for any document. Revocation is delegated to: (a) the user revoking the Passkey in their OS account, (b) the wallet operator removing the DID, (c) issuers revoking issued credentials per their own revocation registry.
Implementations
Section titled “Implementations”| Language | Repo | Notes |
|---|---|---|
| TypeScript | fido-vc-cryptosuite-ts | Reference implementation; used by middleware and verifier sidecar |
| Kotlin / JVM | (planned public release) | Direct in-process integration for JVM verifier stacks; lives in source tree locally |
Where to next
Section titled “Where to next”- Integration Guide — how to plug this into walt.id (or any other verifier)
- Use Cases — where this cryptosuite is intended to be deployed