Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
121 changes: 121 additions & 0 deletions doc/cwt-vc-verification-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# 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. 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`.

---

## 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
CredentialsVerifier->>CwtVerifiableCredential: Verify
CwtVerifiableCredential->>CwtVerifier: Verify
CwtVerifier-->>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.

---
4 changes: 2 additions & 2 deletions vc-verifier/kotlin/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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", name = "cbor", version.ref = "cborLibrary" }
authlete-cbor = { group = "com.authlete", name = "cbor", version.ref = "authleteCbor" }

[plugins]
Expand Down
2 changes: 1 addition & 1 deletion vc-verifier/kotlin/vcverifier/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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}")
}
}

Expand Down