From ede6118fe7f7ed7f149cf8cf0fd9840db6f06687 Mon Sep 17 00:00:00 2001 From: jaswanthkumarpolisetty Date: Wed, 4 Feb 2026 12:14:50 +0530 Subject: [PATCH 1/9] [INJIVER] Update Readme file and add cwt-vc-verification-support doc Signed-off-by: jaswanthkumarpolisetty --- README.md | 1 + doc/cwt-vc-verification-support.md | 119 +++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 doc/cwt-vc-verification-support.md diff --git a/README.md b/README.md index 591fa9b5..146f5c59 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ import io.mosip.vercred.vcverifier.keyResolver.types.http.HttpsPublicKeyResolver | `mso_mdoc` | COSE (CBOR Object Signing and Encryption) | ES256 | Uses COSE_Sign1 | | `vc+sd-jwt` | X.509 Certificate (Currently, JWT VC Issuer Metadata is not supported) | PS256, RS256,ES256, EdDSA (Ed25519) | - | | `dc+sd-jwt` | X.509 Certificate (Currently, JWT VC Issuer Metadata is not supported) | PS256, RS256,ES256, EdDSA (Ed25519) | - | +| `cwt_vc` | COSE_Sign1 (CBOR Web Token – RFC 8392) | ES256, EdDSA (COSE alg based) | COSE_Sign1 | #### Project Structure diff --git a/doc/cwt-vc-verification-support.md b/doc/cwt-vc-verification-support.md new file mode 100644 index 00000000..5080ae23 --- /dev/null +++ b/doc/cwt-vc-verification-support.md @@ -0,0 +1,119 @@ +# Support for IETF CWT Verifiable Credential (CWT-VC) + +This document provides a comprehensive overview of validating and verifying **CWT-based Verifiable Credentials (cwt-vc)** encoded using **CBOR Web Token (CWT)** and **COSE_Sign1**, as defined by IETF standards. + +--- + +## Public key resolution support + +- **HTTP / HTTPS Issuer** + - Retrieves issuer public key from `/.well-known/jwks.json` when `iss` is an HTTP(S) URL. + +--- + +## Steps Involved + +1. Add enum value `CWT_VC("cwt-vc")` in `CredentialFormat`. +2. Create a new class `CwtVerifiableCredential` that implements the `VerifiableCredential` interface. + - `validate` method validates credential structure and claims. + - `verify` method verifies cryptographic signature. +3. Create a class `CwtValidator` to validate credential structure and claims. +4. Create a class `CwtVerifier` to verify the credential signature. +5. Implement validation checks for COSE, headers, claims, and numeric dates. +6. Implement signature verification using issuer public key. +7. Register `CwtVerifiableCredential` in `CredentialVerifierFactory`. + +--- + +## Sequence diagram – validate and verify `cwt-vc` credential + +```mermaid +sequenceDiagram + Wallet->>CredentialsVerifier: verify credential + CredentialsVerifier->>CredentialVerifierFactory: Create verifier + CredentialVerifierFactory->>CwtVerifiableCredential: Create instance + CredentialsVerifier->>CwtVerifiableCredential: Validate + CwtVerifiableCredential->>CwtValidator: Validate + CwtValidator-->>CwtVerifiableCredential: Result + CwtVerifiableCredential-->>CredentialsVerifier: Result +``` + +### Sequence diagram - validation process + +```mermaid +sequenceDiagram + + CwtVerifiableCredential->>CwtValidator: Validate CWT Credential + CwtValidator->>CwtValidator: Validate input is non-empty hex string + CwtValidator->>CwtValidator: Decode hex to CBOR + CwtValidator->>CwtValidator: Validate COSE_Sign1 structure + Note over CwtValidator: COSE_Sign1 must be a CBOR array of size 4 + + CwtValidator->>CwtValidator: Decode protected header + CwtValidator->>CwtValidator: Validate protected header + Note over CwtValidator: alg must be present and must be an integer + + CwtValidator->>CwtValidator: Decode CWT claims + CwtValidator->>CwtValidator: Validate CWT claims structure + Note over CwtValidator: CWT payload must be a CBOR map + + CwtValidator->>CwtValidator: Validate numeric date claims + Note over CwtValidator: exp, nbf, iat are optional numeric dates + + alt exp present and expired + CwtValidator-->>CwtVerifiableCredential: Return Validation Result as False (VC expired) + else nbf present and in future + CwtValidator-->>CwtVerifiableCredential: Return Validation Result as False (Not Before violation) + else iat present and in future + CwtValidator-->>CwtVerifiableCredential: Return Validation Result as False (Invalid iat) + else Validation Success + CwtValidator-->>CwtVerifiableCredential: Return Validation Result as True + end +``` + +### Sequence diagram - verification process + +```mermaid +sequenceDiagram + + CwtVerifiableCredential->>CwtVerifier: Verify CWT Credential + CwtVerifier->>CwtVerifier: Decode hex to CBOR + CwtVerifier->>CwtVerifier: Validate CBOR Tag 61 (CWT) + alt Missing or invalid tag + CwtVerifier-->>CwtVerifiableCredential: Return Verification Result as False + else Valid CWT + CwtVerifier->>CwtVerifier: Extract COSE_Sign1 object + CwtVerifier->>CwtVerifier: Validate COSE_Sign1 structure + CwtVerifier->>CwtVerifier: Extract CWT claims + CwtVerifier->>CwtVerifier: Extract issuer (iss) + CwtVerifier->>CwtVerifier: Extract kid from protected or unprotected header + CwtVerifier->>PublicKeyResolverFactory: Resolve public key using issuer and kid + CwtVerifier->>CwtVerifier: Verify COSE_Sign1 signature + alt Signature Invalid + CwtVerifier-->>CwtVerifiableCredential: Return Verification Result as False + else Signature Valid + CwtVerifier-->>CwtVerifiableCredential: Return Verification Result as True + end + end + + +``` +--- + +## Key Validation Rules Summary + +### COSE Structure +- Must be a CBOR array of exactly 4 elements. + +### Protected Header +- `alg` MUST be present and an integer. + +### CWT Claims +- Payload MUST be a CBOR map. +- `iss`, `exp`, `nbf`, `iat` validated as per spec. + +### Cryptographic Verification +- CBOR tag `61` required. +- Signature verified using COSE_Sign1. + +--- From 57ed42941256b56526d9296cf75d9d6ec2334738 Mon Sep 17 00:00:00 2001 From: jaswanthkumarpolisetty Date: Wed, 4 Feb 2026 12:41:14 +0530 Subject: [PATCH 2/9] [INJIVER] Update Readme file and add cwt-vc-verification-support doc Signed-off-by: jaswanthkumarpolisetty --- doc/cwt-vc-verification-support.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/cwt-vc-verification-support.md b/doc/cwt-vc-verification-support.md index 5080ae23..a01235f2 100644 --- a/doc/cwt-vc-verification-support.md +++ b/doc/cwt-vc-verification-support.md @@ -38,7 +38,7 @@ sequenceDiagram CwtVerifiableCredential-->>CredentialsVerifier: Result ``` -### Sequence diagram - validation process +### Sequence diagram - validation process ```mermaid sequenceDiagram @@ -71,7 +71,7 @@ sequenceDiagram end ``` -### Sequence diagram - verification process +### Sequence diagram - verification process ```mermaid sequenceDiagram From 4f2e7c65772fa0698acacf6282226c484006cfc7 Mon Sep 17 00:00:00 2001 From: jaswanthkumarpolisetty Date: Wed, 4 Feb 2026 13:57:12 +0530 Subject: [PATCH 3/9] =?UTF-8?q?[INJIVER]=20change=20text=20to=20past=20ten?= =?UTF-8?q?se=20in=C2=A0=20Steps=20Involved=20section?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: jaswanthkumarpolisetty --- doc/cwt-vc-verification-support.md | 18 +++++++++--------- vc-verifier/kotlin/gradle/libs.versions.toml | 4 ++-- vc-verifier/kotlin/vcverifier/build.gradle.kts | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/doc/cwt-vc-verification-support.md b/doc/cwt-vc-verification-support.md index a01235f2..414c2c80 100644 --- a/doc/cwt-vc-verification-support.md +++ b/doc/cwt-vc-verification-support.md @@ -13,15 +13,15 @@ This document provides a comprehensive overview of validating and verifying **CW ## Steps Involved -1. Add enum value `CWT_VC("cwt-vc")` in `CredentialFormat`. -2. Create a new class `CwtVerifiableCredential` that implements the `VerifiableCredential` interface. - - `validate` method validates credential structure and claims. - - `verify` method verifies cryptographic signature. -3. Create a class `CwtValidator` to validate credential structure and claims. -4. Create a class `CwtVerifier` to verify the credential signature. -5. Implement validation checks for COSE, headers, claims, and numeric dates. -6. Implement signature verification using issuer public key. -7. Register `CwtVerifiableCredential` in `CredentialVerifierFactory`. +1. Added the enum value `CWT_VC("cwt-vc")` to `CredentialFormat`. +2. Created a new class `CwtVerifiableCredential` that implemented the `VerifiableCredential` interface. + - The `validate` method validated the credential structure and claims. + - The `verify` method verified the cryptographic signature. +3. Created a `CwtValidator` class to validate the credential structure and claims. +4. Created a `CwtVerifier` class to verify the credential signature. +5. Implemented validation checks for COSE, headers, claims, and numeric date fields. +6. Implemented signature verification using the issuer’s public key. +7. Registered `CwtVerifiableCredential` in `CredentialVerifierFactory`. --- diff --git a/vc-verifier/kotlin/gradle/libs.versions.toml b/vc-verifier/kotlin/gradle/libs.versions.toml index 2a65faa0..eef69f5e 100644 --- a/vc-verifier/kotlin/gradle/libs.versions.toml +++ b/vc-verifier/kotlin/gradle/libs.versions.toml @@ -27,7 +27,7 @@ annotationJvm = "1.9.1" cbor = "0.9" identity = "20231002" authleteSdJwt = "1.5" -coseLibrary = "2.0.0" +cborLibrary = "4.5.6" authleteCbor = "1.19" [libraries] @@ -64,7 +64,7 @@ mockWebServer = { group = "com.squareup.okhttp3", name = "mockwebserver", versio annotation-jvm = { group = "androidx.annotation", name = "annotation-jvm", version.ref = "annotationJvm" } cbor = { group = "co.nstant.in", name = "cbor", version.ref = "cbor" } identity = { group = "com.android.identity", name = "identity-credential", version.ref = "identity" } -cose-lib = { group = "se.digg.cose", name = "cose-lib", version.ref = "coseLibrary" } +upokecenter-cbor = { group = "com.upokecenter.cbor", name = "cbor", version.ref = "cborLibrary" } authlete-cbor = { group = "com.authlete", name = "cbor", version.ref = "authleteCbor" } [plugins] diff --git a/vc-verifier/kotlin/vcverifier/build.gradle.kts b/vc-verifier/kotlin/vcverifier/build.gradle.kts index bd273ade..bbe9c1a9 100644 --- a/vc-verifier/kotlin/vcverifier/build.gradle.kts +++ b/vc-verifier/kotlin/vcverifier/build.gradle.kts @@ -68,7 +68,7 @@ dependencies { implementation(libs.annotation.jvm) implementation(libs.authelete.sd.jwt) implementation(libs.threetenbp) - implementation(libs.cose.lib) + implementation(libs.upokecenter.cbor) implementation(libs.authlete.cbor) testImplementation(libs.mockk) From 6e4886e5b9b08267ffcf42ccd15d930ff321befb Mon Sep 17 00:00:00 2001 From: jaswanthkumarpolisetty Date: Wed, 4 Feb 2026 14:42:10 +0530 Subject: [PATCH 4/9] [INJIVER] removed the unused library se.digg.cose and add new library com.upokecenter.cbor Signed-off-by: jaswanthkumarpolisetty --- vc-verifier/kotlin/gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vc-verifier/kotlin/gradle/libs.versions.toml b/vc-verifier/kotlin/gradle/libs.versions.toml index eef69f5e..4a4a9f54 100644 --- a/vc-verifier/kotlin/gradle/libs.versions.toml +++ b/vc-verifier/kotlin/gradle/libs.versions.toml @@ -64,7 +64,7 @@ mockWebServer = { group = "com.squareup.okhttp3", name = "mockwebserver", versio annotation-jvm = { group = "androidx.annotation", name = "annotation-jvm", version.ref = "annotationJvm" } cbor = { group = "co.nstant.in", name = "cbor", version.ref = "cbor" } identity = { group = "com.android.identity", name = "identity-credential", version.ref = "identity" } -upokecenter-cbor = { group = "com.upokecenter.cbor", name = "cbor", version.ref = "cborLibrary" } +upokecenter-cbor = { group = "com.upokecenter", name = "cbor", version.ref = "cborLibrary" } authlete-cbor = { group = "com.authlete", name = "cbor", version.ref = "authleteCbor" } [plugins] From 31bba8c677a339f03457175b49cbfc920cb8b66f Mon Sep 17 00:00:00 2001 From: jaswanthkumarpolisetty Date: Wed, 4 Feb 2026 15:07:10 +0530 Subject: [PATCH 5/9] [INJIVER] added the missing verify details in the sequenceDiagram Signed-off-by: jaswanthkumarpolisetty --- doc/cwt-vc-verification-support.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/cwt-vc-verification-support.md b/doc/cwt-vc-verification-support.md index 414c2c80..46f4137a 100644 --- a/doc/cwt-vc-verification-support.md +++ b/doc/cwt-vc-verification-support.md @@ -34,7 +34,9 @@ sequenceDiagram CredentialVerifierFactory->>CwtVerifiableCredential: Create instance CredentialsVerifier->>CwtVerifiableCredential: Validate CwtVerifiableCredential->>CwtValidator: Validate - CwtValidator-->>CwtVerifiableCredential: Result + CredentialsVerifier->>CwtVerifiableCredential: Verify + CwtVerifiableCredential->>CwtVerifier: Verify + CwtVerifier-->>CwtVerifiableCredential: Result CwtVerifiableCredential-->>CredentialsVerifier: Result ``` From 7f063130ba29163323a5edb00f36f7f8e80d1882 Mon Sep 17 00:00:00 2001 From: jaswanthkumarpolisetty Date: Wed, 4 Feb 2026 15:22:41 +0530 Subject: [PATCH 6/9] [INJIVER] added the new exception unsupportDidUrl Signed-off-by: jaswanthkumarpolisetty --- .../vcverifier/credentialverifier/verifier/CwtVerifier.kt | 3 ++- .../keyResolver/types/jwks/JwksPublicKeyResolver.kt | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt b/vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt index 1a7b0441..fd9e7b7a 100644 --- a/vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt +++ b/vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt @@ -139,7 +139,8 @@ class CwtVerifier { } catch (exception: Exception) { when (exception) { is PublicKeyNotFoundException, - is SignatureVerificationException -> throw exception + is SignatureVerificationException, + is UnsupportedDidUrl -> throw exception else -> throw UnknownException( "Error while verifying CWT credential: ${exception.message}" ) diff --git a/vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/keyResolver/types/jwks/JwksPublicKeyResolver.kt b/vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/keyResolver/types/jwks/JwksPublicKeyResolver.kt index 6623baba..50d63a6f 100644 --- a/vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/keyResolver/types/jwks/JwksPublicKeyResolver.kt +++ b/vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/keyResolver/types/jwks/JwksPublicKeyResolver.kt @@ -30,8 +30,8 @@ class JwksPublicKeyResolver : PublicKeyResolver { return getPublicKeyFromJWK(jwk, kty) } catch (e: Exception) { - logger.severe("Error fetching public key string $e") - throw PublicKeyNotFoundException("Public key string not found") + throw if (e is PublicKeyNotFoundException) e + else PublicKeyNotFoundException("Failed to resolve JWKS public key: ${e.message}") } } From 5d2862c23130100c3ed5ef943d7c3678986c6fb4 Mon Sep 17 00:00:00 2001 From: jaswanthkumarpolisetty Date: Wed, 4 Feb 2026 15:35:14 +0530 Subject: [PATCH 7/9] [INJIVER] remove the new exception unsupportDidUrl Signed-off-by: jaswanthkumarpolisetty --- vc-verifier/kotlin/vcverifier/build.gradle.kts | 1 - .../vcverifier/credentialverifier/verifier/CwtVerifier.kt | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/vc-verifier/kotlin/vcverifier/build.gradle.kts b/vc-verifier/kotlin/vcverifier/build.gradle.kts index bbe9c1a9..9314e88a 100644 --- a/vc-verifier/kotlin/vcverifier/build.gradle.kts +++ b/vc-verifier/kotlin/vcverifier/build.gradle.kts @@ -63,7 +63,6 @@ dependencies { implementation(libs.jackson.annotations) implementation(libs.nimbusJoseJwt) implementation(libs.springWeb) - implementation(libs.cbor) implementation (libs.identity) implementation(libs.annotation.jvm) implementation(libs.authelete.sd.jwt) diff --git a/vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt b/vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt index fd9e7b7a..1a7b0441 100644 --- a/vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt +++ b/vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt @@ -139,8 +139,7 @@ class CwtVerifier { } catch (exception: Exception) { when (exception) { is PublicKeyNotFoundException, - is SignatureVerificationException, - is UnsupportedDidUrl -> throw exception + is SignatureVerificationException -> throw exception else -> throw UnknownException( "Error while verifying CWT credential: ${exception.message}" ) From 729dc503286508d69fcedd8d52403523148ba21d Mon Sep 17 00:00:00 2001 From: jaswanthkumarpolisetty Date: Wed, 4 Feb 2026 15:39:23 +0530 Subject: [PATCH 8/9] [INJIVER] add the lib.cbor back Signed-off-by: jaswanthkumarpolisetty --- vc-verifier/kotlin/vcverifier/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/vc-verifier/kotlin/vcverifier/build.gradle.kts b/vc-verifier/kotlin/vcverifier/build.gradle.kts index 9314e88a..bbe9c1a9 100644 --- a/vc-verifier/kotlin/vcverifier/build.gradle.kts +++ b/vc-verifier/kotlin/vcverifier/build.gradle.kts @@ -63,6 +63,7 @@ dependencies { implementation(libs.jackson.annotations) implementation(libs.nimbusJoseJwt) implementation(libs.springWeb) + implementation(libs.cbor) implementation (libs.identity) implementation(libs.annotation.jvm) implementation(libs.authelete.sd.jwt) From 9844c5919373f2ec3283bc147cbeffcad2150032 Mon Sep 17 00:00:00 2001 From: jaswanthkumarpolisetty Date: Wed, 4 Feb 2026 15:56:02 +0530 Subject: [PATCH 9/9] [INJIVER] use initCause() to attach the original exception Signed-off-by: jaswanthkumarpolisetty --- .../vcverifier/keyResolver/types/jwks/JwksPublicKeyResolver.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/keyResolver/types/jwks/JwksPublicKeyResolver.kt b/vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/keyResolver/types/jwks/JwksPublicKeyResolver.kt index 50d63a6f..58cc9813 100644 --- a/vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/keyResolver/types/jwks/JwksPublicKeyResolver.kt +++ b/vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/keyResolver/types/jwks/JwksPublicKeyResolver.kt @@ -31,7 +31,7 @@ class JwksPublicKeyResolver : PublicKeyResolver { return getPublicKeyFromJWK(jwk, kty) } catch (e: Exception) { throw if (e is PublicKeyNotFoundException) e - else PublicKeyNotFoundException("Failed to resolve JWKS public key: ${e.message}") + else PublicKeyNotFoundException("Failed to resolve JWKS public key: ${e.message}").apply { initCause(e) } } }