-
Notifications
You must be signed in to change notification settings - Fork 22
[INJIVER-1369] - Add verification and validation for cwt formet VC with new library #216
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
Signed-off-by: jaswanthkumarpolisetty <jaswanthkumar.p@thoughtworks.com>
Signed-off-by: jaswanthkumarpolisetty <jaswanthkumar.p@thoughtworks.com>
Signed-off-by: jaswanthkumarpolisetty <jaswanthkumar.p@thoughtworks.com>
WalkthroughAdds CWT (CBOR Web Token) verifiable credential support: new validator/verifier classes, enum and constants, factory routing, utilities, tests, COSE dependency, build exclusions, and example app changes to verify CWT hex input. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant CV as CredentialVerifier
participant Cwt as CwtVerifiableCredential
participant Val as CwtValidator
participant Ver as CwtVerifier
participant PKR as PublicKeyResolver
participant COSE as COSE Lib
Client->>CV: verify(cwtHex, CWT_VC)
CV->>Cwt: verify(cwtHex)
rect rgb(220,235,255)
Note over Val: Validation Phase
Cwt->>Val: validate(cwtHex)
Val->>COSE: decode COSE_Sign1 (hex→bytes)
COSE-->>Val: CBORObject
Val->>Val: validate structure, header, payload
Val->>Val: validate exp/nbf/iat
Val-->>Cwt: ValidationStatus
end
rect rgb(220,255,220)
Note over Ver: Verification Phase
Cwt->>Ver: verify(cwtHex)
Ver->>COSE: decode COSE_Sign1
COSE-->>Ver: CBORObject
Ver->>Ver: extract issuer & signature
Ver->>PKR: resolvePublicKey(issuer)
PKR-->>Ver: PublicKey
Ver->>Ver: verify signature
Ver-->>Cwt: Boolean
end
Cwt-->>CV: VerificationResult
CV-->>Client: result
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
🤖 Fix all issues with AI Agents
In @vc-verifier/kotlin/gradle/libs.versions.toml:
- Around line 23-24: The jackson dependency versions are inconsistent:
libs.versions.toml sets jacksonAnnotations and jacksonModuleKotlin to 2.17.2
while vcverifier/build.gradle.kts forces jackson-core:2.14.0; update the forced
dependency in build.gradle.kts (the jackson-core version pin around the
dependency declaration) to 2.17.2 to match
jacksonAnnotations/jacksonModuleKotlin, ensure jackson-module-kotlin and
jackson-core are aligned, then run and validate Jackson-dependent code (Kotlin
serialization/deserialization, polymorphic JsonTypeInfo, enum handling and any
code that may be affected by StreamRead/Write and coercion changes) to address
breaking changes introduced between 2.14.0 and 2.17.2.
In @vc-verifier/kotlin/vcverifier/build.gradle.kts:
- Around line 76-81: The global exclusions in the configurations.all block are
removing the same BouncyCastle artifact you explicitly add via
implementation(libs.bouncyCastle) and conflict with other configurations.all
blocks; replace the global exclusions with per-dependency excludes on the
dependencies that bring in the unwanted bcprov/bcpkix/bcutil transitive
artifacts (e.g., update implementation(libs.cose.lib) and any other dependency
entries that transitively pull BouncyCastle to add
exclude(group="org.bouncycastle", module="bcprov-jdk15on") /
exclude(group="org.bouncycastle", module="bcpkix-jdk15on") /
exclude(group="org.bouncycastle", module="bcutil-jdk15on") so you can keep
implementation(libs.bouncyCastle) while removing only the conflicting transitive
versions and remove the contradictory configurations.all exclusions.
- Line 68: The dependency declaration implementation(libs.cose.lib) references
se.digg.cose:cose-lib version 2.0.0 which is not on Maven Central; either
confirm the required repository (e.g., Danubetech or JitPack) is added to the
Gradle repositories block or change the version to one that is published (update
the libs.versions or the explicit version in build.gradle.kts). Locate the
implementation(libs.cose.lib) entry and ensure the repository that hosts
se.digg.cose:cose-lib is configured (or replace libs.cose.lib with a resolvable
version) so the project can resolve the dependency during build.
In
@vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt:
- Line 3: The import android.net.Uri in CwtVerifier.kt is unused and
Android-specific; remove the unused import statement from the top of the file
(the line importing android.net.Uri) so the CwtVerifier class and its functions
compile cleanly in non-Android JVM environments.
- Around line 19-26: Remove the duplicate local function hexToBytes from
CwtVerifier and replace its usages with the existing utility: call
Util.hexToBytes(...) (or add the single-function import
io.mosip.vercred.vcverifier.utils.Util.hexToBytes and call hexToBytes(...));
ensure all references inside CwtVerifier that previously called the local
hexToBytes now call the util method and delete the redundant function
definition.
- Around line 139-153: In verify(credential) fix missing error handling around
PublicKeyResolverFactory().get(issuer) by wrapping the call in a try-catch and
returning false if it throws, and also check the returned publicKey for null and
return false before calling verifySignature(coseBytes, publicKey); additionally
remove the unnecessary semicolons after statements (e.g., the semicolons after
decodeCose(...), isValidCoseStructure(...), CBORObject.DecodeFromBytes(...), and
isValidCwtStructure(...)) so the method consistently follows the defensive
return-false pattern.
- Around line 77-117: Dead-code: fetchPublicKey and extractKid implement JWKS
resolution but are never used; either remove them or wire them into the
verification flow. To fix, either delete the unused methods fetchPublicKey(...)
and extractKid(...) (clean up imports) or modify the verify() path that
currently uses PublicKeyResolverFactory to call fetchPublicKey(coseObj,
issuerMetadataJson) (or a new adapter method) and fall back to
PublicKeyResolverFactory if fetchPublicKey returns null; ensure the verify()
caller supplies issuerMetadataJson (parse issuer metadata where needed) and
handle null PublicKey results consistently with existing error handling.
In
@vc-verifier/kotlin/vcverifier/src/test/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifierTest.kt:
- Around line 22-92: The CwtVerifierTest's entire test method `should verify
valid CWT` is commented out leaving CwtVerifier untested; either re-enable and
fix the test, remove it with a TODO and issue, or document why it's disabled. To
fix: restore the test in class `CwtVerifierTest` (uncomment the `should verify
valid CWT` method), ensure necessary imports and test annotations are present,
fix any runtime issues by mocking `Util.httpGet` correctly (the current mock
targets `Util.httpGet(any())` and must return the `issuerMetadataJson` and
`jwksJson` for `"$issuer/.well-known/openid-credential-issuer"` and
`"$issuer/jwks"`), and verify the COSE creation code (references:
`Sign1COSEObject`, `COSEKey`, `ECKey.Builder`, `KeyPairGenerator`) compiles and
the asserted call `CwtVerifier().verify(coseHex)` returns true; alternatively,
if intentionally disabled remove the commented block in `CwtVerifierTest` and
add a single-line TODO with a tracking issue referencing `CwtVerifier` and
`should verify valid CWT`.
🧹 Nitpick comments (11)
vc-verifier/kotlin/example/build.gradle.kts (1)
51-51: Consider documenting the reason for this exclusion.The exclusion of
META-INF/versions/9/OSGI-INF/MANIFEST.MFsuggests a duplicate resource conflict, likely introduced by the new COSE library or updated dependencies. While this exclusion is valid, consider adding a comment explaining which dependency causes the conflict to help future maintainers.🔎 Suggested improvement
excludes += "/META-INF/{AL2.0,LGPL2.1}" + // Exclude duplicate OSGI manifest from cose-lib or transitive dependencies excludes += "META-INF/versions/9/OSGI-INF/MANIFEST.MF"vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/constants/CredentialValidatorConstants.kt (1)
55-58: Fix formatting and consider adding error codes for consistency.Formatting issues:
- Missing space after
=operator on lines 55 and 57 (inconsistent with the rest of the file)- Unnecessary blank lines at lines 56 and 58 (breaks the file's consistent spacing pattern)
Optional improvement:
Similar toERROR_MESSAGE_EMPTY_VC_JSONhaving a correspondingERROR_CODE_EMPTY_VC_JSON(lines 36, 42), consider adding error codes for the new CWT constants (e.g.,ERROR_CODE_EMPTY_VC_CWTandERROR_CODE_INVALID_HEX_VC_CWT) to maintain consistency across validation error handling.🔎 Proposed formatting fix
- const val ERROR_MESSAGE_EMPTY_VC_CWT="${VALIDATION_ERROR}Input VC CWT string is null or empty." - - const val ERROR_MESSAGE_INVALID_HEX_VC_CWT="${VALIDATION_ERROR}Invalid hexadecimal format" - + const val ERROR_MESSAGE_EMPTY_VC_CWT = "${VALIDATION_ERROR}Input VC CWT string is null or empty." + const val ERROR_MESSAGE_INVALID_HEX_VC_CWT = "${VALIDATION_ERROR}Invalid hexadecimal format"vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/types/CwtVerifiableCredential.kt (1)
14-20: Remove unnecessary semicolons and consider documenting the no-opcheckStatus.Kotlin doesn't require semicolons. Additionally, consider adding a
TODOcomment tocheckStatusif status checking for CWT credentials is planned for future implementation, or document why it's intentionally a no-op.🔎 Proposed fix
override fun verify(credential: String): Boolean { - return CwtVerifier().verify(credential); + return CwtVerifier().verify(credential) } + // TODO: Implement status checking for CWT credentials if required override fun checkStatus(credential: String, statusPurposes: List<String>?): Map<String, CredentialStatusResult> { - return emptyMap(); + return emptyMap() }vc-verifier/kotlin/vcverifier/src/test/java/io/mosip/vercred/vcverifier/credentialverifier/validator/CwtValidatorTest.kt (2)
13-15: Remove the emptysetup()method.The empty
@BeforeEachmethod adds no value and was flagged by static analysis.🔎 Proposed fix
- @BeforeEach - fun setup() { - } - private val validator = CwtValidator()
34-46: Consider consistent test naming convention.Test method names use inconsistent prefixes (
validate -vstest -). Consider standardizing to a single pattern for better readability and organization.vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/utils/Util.kt (3)
36-36: Consider makingrestTemplateprivate.Exposing
restTemplateas a public val leaks the internal HTTP implementation. If external access is needed, consider providing a factory method or making it internal/private.🔎 Proposed fix
- val restTemplate = RestTemplate() + private val restTemplate = RestTemplate()
152-159:hexToBytesthrows unchecked exception on invalid hex characters.If the input contains non-hex characters (e.g., "ZZ"),
toInt(16)throwsNumberFormatException. WhileCwtValidatorvalidates hex before calling this, other callers may not. Consider adding character validation or documenting the precondition.🔎 Proposed fix
fun hexToBytes(hex: String): ByteArray { val cleanHex = hex.replace("\\s".toRegex(), "") require(cleanHex.length % 2 == 0) { "Invalid hex length" } + require(cleanHex.matches("^[0-9a-fA-F]*$".toRegex())) { "Invalid hex characters" } return ByteArray(cleanHex.length / 2) { i -> cleanHex.substring(i * 2, i * 2 + 2).toInt(16).toByte() } }
177-183: Consider logging HTTP failures for debuggability.Silently returning
nullon any exception (network errors, timeouts, HTTP 4xx/5xx) can make debugging difficult. Consider logging at debug/trace level.vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/validator/CwtValidator.kt (2)
130-135: UseisIntegral()instead ofisNumberfor stricteralgvalidation.Per COSE specification,
algmust be an integer, not a floating-point number.isNumberreturns true for floats as well. Consider usingisIntegral()for stricter validation.🔎 Proposed fix
- if (!protectedHeader[ALG].isNumber) { + if (!protectedHeader[ALG].isIntegral) { throw ValidationException( ERROR_INVALID_FIELD + "alg must be an integer", ERROR_CODE_INVALID + "ALG" ) }
204-207: Inconsistency withUtil.hexToByteswhitespace handling.
isValidHexrejects any whitespace, butUtil.hexToBytesstrips whitespace before processing. Consider aligning behavior - either allow whitespace in validation (strip before regex check) or document that whitespace is not permitted.🔎 Proposed fix to align with Util.hexToBytes
private fun isValidHex(credential: String): Boolean { + val cleanCredential = credential.replace("\\s".toRegex(), "") val hexRegex = "^[0-9a-fA-F]+$".toRegex() - return credential.matches(hexRegex) + return cleanCredential.isNotEmpty() && cleanCredential.matches(hexRegex) }vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt (1)
14-14: Remove unused importjava.net.URL.🔎 Proposed fix
-import java.net.URL
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
vc-verifier/kotlin/example/build.gradle.ktsvc-verifier/kotlin/example/src/main/java/io/mosip/vccred/example/MainActivity.ktvc-verifier/kotlin/gradle/libs.versions.tomlvc-verifier/kotlin/vcverifier/build.gradle.ktsvc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/constants/CredentialFormat.ktvc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/constants/CredentialValidatorConstants.ktvc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/CredentialVerifierFactory.ktvc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/types/CwtVerifiableCredential.ktvc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/validator/CwtValidator.ktvc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.ktvc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/utils/Util.ktvc-verifier/kotlin/vcverifier/src/test/java/io/mosip/vercred/vcverifier/credentialverifier/validator/CwtValidatorTest.ktvc-verifier/kotlin/vcverifier/src/test/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifierTest.kt
👮 Files not reviewed due to content moderation or server errors (1)
- vc-verifier/kotlin/example/src/main/java/io/mosip/vccred/example/MainActivity.kt
🧰 Additional context used
🧬 Code graph analysis (2)
vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/validator/CwtValidator.kt (1)
vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/utils/Util.kt (2)
validateNumericDate(161-175)hexToBytes(152-159)
vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt (1)
vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/utils/Util.kt (2)
hexToBytes(152-159)httpGet(177-183)
🪛 detekt (1.23.8)
vc-verifier/kotlin/vcverifier/src/test/java/io/mosip/vercred/vcverifier/credentialverifier/validator/CwtValidatorTest.kt
[warning] 14-15: This empty block of code can be removed.
(detekt.empty-blocks.EmptyFunctionBlock)
🔇 Additional comments (4)
vc-verifier/kotlin/gradle/libs.versions.toml (1)
30-30: LGTM! New COSE library properly configured.The new
coseLibraryversion reference andcose-liblibrary alias are correctly defined and follow the existing conventions in the version catalog.Also applies to: 66-66
vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/CredentialVerifierFactory.kt (1)
4-4: LGTM! Factory properly extended for CWT format.The addition of
CwtVerifiableCredentialto the factory follows the existing pattern and correctly handles the newCredentialFormat.CWT_VCformat.Also applies to: 16-16
vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/constants/CredentialFormat.kt (1)
4-4: LGTM! New credential format added correctly.The
CWT_VCenum constant follows the existing naming pattern and integrates seamlessly with thefromValue()method.vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/validator/CwtValidator.kt (1)
24-59: LGTM - Clean validation flow with proper error handling.The validation structure is well-organized with clear separation between structure validation, header validation, and date validation. Exception-based control flow provides consistent error reporting.
| jacksonAnnotations = "2.17.2" | ||
| jacksonModuleKotlin = "2.17.2" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓ Verification inconclusive
Script executed:
#!/bin/bash
# Check for forced Jackson versions in build files
rg -n "jackson-core" --type kotlin -A 2 -B 2Repository: inji/vc-verifier
Repository: inji/vc-verifier
Exit code: 0
stdout:
vc-verifier/kotlin/vcverifier/build.gradle.kts-10-
vc-verifier/kotlin/vcverifier/build.gradle.kts-11-configurations.all {
vc-verifier/kotlin/vcverifier/build.gradle.kts:12: resolutionStrategy.force( "com.fasterxml.jackson.core:jackson-core:2.14.0")
vc-verifier/kotlin/vcverifier/build.gradle.kts-13-}
vc-verifier/kotlin/vcverifier/build.gradle.kts-14-
Jackson 2.14.0 to 2.17.2 breaking changes migration guide
Summary of notable breaking changes and migration steps when moving from Jackson 2.14.0 → 2.17.2
Quick guidance
- Read the official release pages for 2.15, 2.16 and 2.17.2 and test your code against each minor release (2.15 → 2.16 → 2.17.2). [1][2][3]
Breaking / behavioral changes to watch for (actionable items)
- Processing limits and stricter parsing defaults
- New StreamRead/Write constraints (max token lengths, nesting, string length, property-name length) and defaults that may reject extremely large or deeply-nested input. Configure StreamReadConstraints/StreamWriteConstraints on JsonFactory if you need previous behavior. [1][2]
- Change to INCLUDE_SOURCE_IN_LOCATION default
- StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION default changed to false (less source info in exceptions). If you rely on source in error messages, explicitly enable it. [2]
- Number/string coercion and parsing stricter rules
- 2.17 tightened "stringified" number coercion (e.g., "07") and 2.17.2 relaxed some number parsing edge-cases (e.g., trailing dot handling); test numeric deserializations and adjust DeserializationFeature or custom deserializers if needed. [3][2]
- JsonTypeInfo and polymorphic type handling
- New JsonTypeInfo.Value, OptBoolean option, and JsonTypeInfo.Id.SIMPLE_NAME were added; polymorphic/type-id behavior changed in places — validate polymorphic deserialization and adjust annotations/config if necessary. [2]
- Enum handling and annotations
- Improved/changed enum annotation support and enum naming strategies (new @EnumNaming/EnumNamingStrategy in 2.15); tests for enum serialization/deserialization may reveal behavioral differences. [1][2]
- Kotlin/Scala modules
- Module compatibility changes: Kotlin module support ranges changed (2.15→2.16) and Kotlin-specific behaviors (getter/is- names, exception types) changed — upgrade jackson-module-kotlin and re-run Kotlin tests. Scala module updates also in 2.16. [1][2]
- Jakarta / Jakarta-RS provider changes
- Jakarta variants and some provider classes were moved/changed (see jakarta/jax-rs related module refactors). If you use javax→jakarta migrations, check the jakarta-variants of modules. [1][3]
- Module and dependency changes
- Several modules added/adjusted (android-record, jackson-datatype-hibernate6, jackson-module-jsonSchema-jakarta) and transitive dependency updates (SnakeYAML, Woodstox, Guava). Verify classpath conflicts and update dependent modules accordingly. [1][2][3]
- Exception and API changes in Kotlin/Java interop
- Some exceptions replaced (e.g., MissingKotlinParameterException → MismatchedInputException); adjust exception handling if you caught the old types. [2]
- Misc bugfixes that may change previously relied-on behavior
- Numerous bug fixes across databind/core/format modules (see patch notes in 2.16.1 and 2.17.2); some fixes (e.g., JsonSetter handling, JsonNode findValues, Reactor lock issues) can alter runtime behavior — run full regression tests. [2][3]
Recommended migration checklist
- Upgrade and test incrementally: 2.14.0 → 2.15.x → 2.16.x → 2.17.2. Run unit + integration tests at each step. [1][2][3]
- Run security/static-analysis and dependency checks for transitive changes (SnakeYAML, Woodstox, Jakarta vs javax).
- If you parse untrusted input, review and tune new StreamRead/WriteConstraints (token lengths, nesting limits). [1][2]
- Pin or align modules (jackson-core/databind/annotations and language modules) to the same version series to avoid incompatibilities.
- Update jackson-module-kotlin / jackson-module-scala to matching versions and re-run language-specific tests. [1][2]
- Search your codebase for places relying on previous lax parsing (stringified numbers, extremely long tokens, exception classes) and add targeted fixes or config flags.
Primary sources (read in full during migration)
- Jackson 2.15 release notes (changes, processing limits, enum features, kotlin notes). [1]
- Jackson 2.16 release notes (INCLUDE_SOURCE_IN_LOCATION default change, StreamWriteConstraints, JsonTypeInfo changes). [2]
- Jackson 2.17 / 2.17.2 release & patch notes (behavior tweaks, bugfixes). [3]
References
[1] Jackson Release 2.15 — FasterXML/jackson Wiki.
[2] Jackson Release 2.16 (and 2.16.1) — FasterXML/jackson Wiki.
[3] Jackson Release 2.17 and 2.17.2 — FasterXML/jackson Wiki.
If you want, I can produce a tailored checklist for your codebase: tell me which Jackson modules you use (core, databind, kotlin, xml, yaml, etc.) and any areas you’re most concerned about (polymorphism, enums, Kotlin interop, security limits).
Resolve Jackson version mismatch between libs.versions.toml and build.gradle.kts.
The Jackson version has been bumped to 2.17.2 in libs.versions.toml (lines 23-24), but vc-verifier/kotlin/vcverifier/build.gradle.kts line 12 still forces jackson-core:2.14.0, creating a version conflict. This mismatch will cause classpath issues and inconsistent behavior.
Additionally, Jackson 2.14.0 → 2.17.2 includes significant breaking changes that require validation:
- Stricter parsing defaults (StreamRead/Write constraints on token lengths, nesting depth)
- Changed default for
INCLUDE_SOURCE_IN_LOCATION(affects exception messages) - Tightened number/string coercion rules
- Kotlin module compatibility changes (
jackson-module-kotlinmust align withjackson-coreversion) - JsonTypeInfo and enum handling modifications
Update build.gradle.kts line 12 to align with the 2.17.2 version, then test Jackson-dependent code, particularly Kotlin-specific serialization/deserialization and polymorphic type handling.
🤖 Prompt for AI Agents
In @vc-verifier/kotlin/gradle/libs.versions.toml around lines 23 - 24, The
jackson dependency versions are inconsistent: libs.versions.toml sets
jacksonAnnotations and jacksonModuleKotlin to 2.17.2 while
vcverifier/build.gradle.kts forces jackson-core:2.14.0; update the forced
dependency in build.gradle.kts (the jackson-core version pin around the
dependency declaration) to 2.17.2 to match
jacksonAnnotations/jacksonModuleKotlin, ensure jackson-module-kotlin and
jackson-core are aligned, then run and validate Jackson-dependent code (Kotlin
serialization/deserialization, polymorphic JsonTypeInfo, enum handling and any
code that may be affected by StreamRead/Write and coercion changes) to address
breaking changes introduced between 2.14.0 and 2.17.2.
| implementation(libs.annotation.jvm) | ||
| implementation(libs.authelete.sd.jwt) | ||
| implementation(libs.threetenbp) | ||
| implementation(libs.cose.lib) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
se.digg.cose:cose-lib 2.0.0 Maven Central availability
💡 Result:
se.digg.cose:cose-lib version 2.0.0 is not published to Maven Central (no 2.0.0 version listed for that G:A). See the project listing (notes that publishing to Maven Central was planned) and the Sonatype Central artifact page (no published versions shown). [1][2]
Sources:
[1] libraries.io project page for se.digg.cose:cose-lib.
[2] Sonatype/Maven Central artifact page for se.digg.cose:cose-lib.
🌐 Web query:
se.digg.cose:cose-lib security vulnerabilities CVE
💡 Result:
I couldn't find any public CVE entries tied to the Maven artifact se.digg.cose:cose-lib. Maven Central / mvnrepository and project pages show the library but list no CVEs/vulnerability entries. Sources: [Maven Central / Sonatype],[MvnRepository],[Libraries.io / project page].
If you want, I can (a) run targeted CVE/NVD searches and vendor advisories for specific versions, or (b) scan a given jar for known vulnerable dependency signatures — which would be more thorough.
Sources:
[1] Maven Central / artifact page (se.digg.cose:cose-lib).
[2] MvnRepository entry for se.digg.cose:cose-lib.
[3] Libraries.io project summary for se.digg.cose:cose-lib.
🏁 Script executed:
grep -r "repository\|maven" vc-verifier/kotlin/vcverifier/build.gradle.ktsRepository: inji/vc-verifier
Length of output: 79
🏁 Script executed:
grep -r "cose" vc-verifier/kotlin/vcverifier/ --include="*.toml" --include="*.gradle.kts"Repository: inji/vc-verifier
Length of output: 140
🏁 Script executed:
find . -name "libs.versions.toml" -o -name "settings.gradle.kts" | head -5Repository: inji/vc-verifier
Length of output: 147
🏁 Script executed:
cat gradle/libs.versions.toml 2>/dev/null || cat libs.versions.toml 2>/dev/null || find . -name "libs.versions.toml" -exec cat {} \;Repository: inji/vc-verifier
Length of output: 4281
🏁 Script executed:
cat vc-verifier/kotlin/settings.gradle.ktsRepository: inji/vc-verifier
Length of output: 738
Version 2.0.0 of se.digg.cose:cose-lib is not available on Maven Central. Verify that this version exists in the configured custom repositories (Danubetech, JitPack) or update to an available version. If the dependency cannot be resolved, the build will fail.
🤖 Prompt for AI Agents
In @vc-verifier/kotlin/vcverifier/build.gradle.kts at line 68, The dependency
declaration implementation(libs.cose.lib) references se.digg.cose:cose-lib
version 2.0.0 which is not on Maven Central; either confirm the required
repository (e.g., Danubetech or JitPack) is added to the Gradle repositories
block or change the version to one that is published (update the libs.versions
or the explicit version in build.gradle.kts). Locate the
implementation(libs.cose.lib) entry and ensure the repository that hosts
se.digg.cose:cose-lib is configured (or replace libs.cose.lib with a resolvable
version) so the project can resolve the dependency during build.
...erifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt
Outdated
Show resolved
Hide resolved
...erifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt
Outdated
Show resolved
Hide resolved
...ier/src/test/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifierTest.kt
Outdated
Show resolved
Hide resolved
Signed-off-by: jaswanthkumarpolisetty <jaswanthkumar.p@thoughtworks.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In
@vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt:
- Around line 19-26: Remove the duplicate hexToBytes function from CwtVerifier
and replace any internal calls to hexToBytes with Util.hexToBytes; specifically,
delete the fun hexToBytes(...) definition in CwtVerifier.kt, add the appropriate
import or fully qualify calls to Util.hexToBytes wherever this local function
was used, and ensure compilation by resolving any missing imports or references
to the Util class.
- Around line 105-129: The call PublicKeyResolverFactory().get(issuer) can
return null; before calling verifySignature(coseBytes, publicKey) add a null
check and throw PublicKeyNotFoundException (or a suitable exception) with a
clear message including the issuer when publicKey is null; ensure the existing
catch block still propagates PublicKeyNotFoundException so callers see the
specific failure rather than a NullPointerException.
In
@vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/keyResolver/types/did/DidWebPublicKeyResolver.kt:
- Around line 40-42: The current use of substring matching in
verificationMethods.find ((it[ID] as? String)?.contains(verificationMethodId) ==
true) can resolve the wrong key; change the matching to exact equality: compare
the ID string exactly to verificationMethodId (or, if you must support
fragment/URI variants, perform a deterministic comparison such as URI
normalization and exact equality or use suffix/fragment-only matching like
endsWith after validating the scheme) so that verificationMethod selection via
verificationMethodId is unambiguous and not order-dependent.
🧹 Nitpick comments (2)
vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt (2)
58-75: Remove unusedextractKidmethod.This method extracts the Key ID from the COSE header but is never called. The
verify()method resolves the public key using only the issuer URI viaPublicKeyResolverFactory, bypassing any KID-based resolution.Either remove this dead code or integrate KID-based key resolution into the verification flow if needed.
28-35: Log swallowed exception indecodeCose.The caught exception is silently swallowed when CBOR decoding fails. This makes debugging difficult when malformed credentials are provided.
📝 Add logging
private fun decodeCose(cwtBytes: ByteArray): CBORObject? { return try { CBORObject.DecodeFromBytes(cwtBytes) } catch (e: Exception) { - + logger.warning("Failed to decode COSE object: ${e.message}") null } }Based on static analysis hints.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
vc-verifier/kotlin/example/src/main/java/io/mosip/vccred/example/MainActivity.ktvc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.ktvc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/keyResolver/types/did/DidWebPublicKeyResolver.ktvc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/utils/Util.ktvc-verifier/kotlin/vcverifier/src/test/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifierTest.kt
🚧 Files skipped from review as they are similar to previous changes (1)
- vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/utils/Util.kt
👮 Files not reviewed due to content moderation or server errors (1)
- vc-verifier/kotlin/example/src/main/java/io/mosip/vccred/example/MainActivity.kt
🧰 Additional context used
🧬 Code graph analysis (1)
vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt (1)
vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/utils/Util.kt (1)
hexToBytes(149-156)
🪛 detekt (1.23.8)
vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt
[warning] 70-70: The caught exception is swallowed. The original exception could be lost.
(detekt.exceptions.SwallowedException)
[warning] 87-87: The caught exception is swallowed. The original exception could be lost.
(detekt.exceptions.SwallowedException)
...erifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt
Outdated
Show resolved
Hide resolved
...erifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt
Show resolved
Hide resolved
...r/src/main/java/io/mosip/vercred/vcverifier/keyResolver/types/did/DidWebPublicKeyResolver.kt
Show resolved
Hide resolved
Signed-off-by: jaswanthkumarpolisetty <jaswanthkumar.p@thoughtworks.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In
@vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt:
- Around line 29-36: Remove the unused helper method decodeCose: it's never
invoked (verify() calls CBORObject.DecodeFromBytes() directly), so delete the
private fun decodeCose(cwtBytes: ByteArray): CBORObject? declaration and its
body to eliminate dead code; if you prefer keeping an abstraction, refactor
verify() to call decodeCose instead, but do not leave an unused decodeCose
method in the class.
- Around line 64-81: The extractKid(CBORObject) method is unused; either remove
it or wire it into the verification path: update verify() in CwtVerifier to call
extractKid(coseObj) and, when a KID is returned, use it to select the matching
key from the resolved JWKS (prefer the KID-matching JWK when constructing the
public key), falling back to issuer-based resolution if no KID or no match;
ensure null-safe handling and remove extractKid if you choose deletion, along
with any now-unused imports.
🧹 Nitpick comments (1)
vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt (1)
20-27: Remove duplicatehexToBytes- useUtil.hexToBytesinstead.This function duplicates
Util.hexToBytesfrom the utilities package. Maintaining duplicate code violates DRY and increases maintenance burden.♻️ Proposed fix
Import and use the existing utility:
+import io.mosip.vercred.vcverifier.utils.Util + class CwtVerifier { private val logger = Logger.getLogger(CwtVerifier::class.java.name) - fun hexToBytes(hex: String): ByteArray { - val cleanHex = hex.replace("\\s".toRegex(), "") - require(cleanHex.length % 2 == 0) { "Invalid hex length" } - - return ByteArray(cleanHex.length / 2) { i -> - cleanHex.substring(i * 2, i * 2 + 2).toInt(16).toByte() - } - }Then replace the call at line 115:
- val coseBytes = hexToBytes(credential) + val coseBytes = Util.hexToBytes(credential)
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.ktvc-verifier/kotlin/vcverifier/src/test/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifierTest.kt
🚧 Files skipped from review as they are similar to previous changes (1)
- vc-verifier/kotlin/vcverifier/src/test/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifierTest.kt
🧰 Additional context used
🧬 Code graph analysis (1)
vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt (1)
vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/utils/Util.kt (1)
hexToBytes(149-156)
🪛 detekt (1.23.8)
vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt
[warning] 32-32: The caught exception is swallowed. The original exception could be lost.
(detekt.exceptions.SwallowedException)
[warning] 125-125: The caught exception is swallowed. The original exception could be lost.
(detekt.exceptions.SwallowedException)
...erifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt
Outdated
Show resolved
Hide resolved
...erifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt
Outdated
Show resolved
Hide resolved
Signed-off-by: jaswanthkumarpolisetty <jaswanthkumar.p@thoughtworks.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In
@vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt:
- Around line 48-65: Delete the entire commented-out extractKid method block in
CwtVerifier (the commented function named extractKid) to remove dead code;
ensure no remaining references to extractKid exist in the class or callers, run
a build/compile to confirm nothing breaks, and commit the cleanup so Git history
retains the implementation if needed.
- Around line 106-112: The JavaDoc and exception handling around resolving the
public key are inaccurate: PublicKeyResolverFactory.get(issuer) returns a
non-null PublicKey so remove any null-checks, update the JavaDoc on the val
publicKey statement to state it resolves and returns a non-null PublicKey and
declare/cite that it may throw PublicKeyTypeNotSupportedException (not
PublicKeyNotFoundException), and change the catch/rethrow logic that currently
references PublicKeyNotFoundException to instead catch and handle or rethrow
PublicKeyTypeNotSupportedException so the actual thrown exception is handled
when calling PublicKeyResolverFactory.get and before calling
verifySignature(coseBytes, publicKey).
🧹 Nitpick comments (1)
vc-verifier/kotlin/vcverifier/build.gradle.kts (1)
13-15: Consider using per-dependency exclusions for better maintainability.Global exclusions in
configurations.allwork but can be less explicit about which dependencies cause conflicts. Consider applying exclusions directly on dependencies that transitively bring in older BouncyCastle versions (e.g., on line 71'slibs.cose.lib).♻️ Alternative approach with per-dependency exclusions
configurations.all { resolutionStrategy.force( "com.fasterxml.jackson.core:jackson-core:2.14.0") - exclude(group = "org.bouncycastle", module = "bcprov-jdk15on") - exclude(group = "org.bouncycastle", module = "bcpkix-jdk15on") - exclude(group = "org.bouncycastle", module = "bcutil-jdk15on") }Then apply exclusions where they're actually needed:
implementation(libs.cose.lib) { exclude(group = "org.bouncycastle", module = "bcprov-jdk15on") exclude(group = "org.bouncycastle", module = "bcpkix-jdk15on") exclude(group = "org.bouncycastle", module = "bcutil-jdk15on") }This makes it clear which dependencies introduce the conflicting BouncyCastle versions.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
vc-verifier/kotlin/vcverifier/build.gradle.ktsvc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt
🧰 Additional context used
🧬 Code graph analysis (1)
vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt (1)
vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/utils/Util.kt (1)
hexToBytes(149-156)
🔇 Additional comments (5)
vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt (5)
1-21: LGTM! Clean imports and setup.The imports are well-organized, and the past issue with the Android-specific import has been properly addressed. Using
Util.hexToBytesavoids code duplication.
22-26: LGTM! Correct COSE_Sign1 structure validation.The validation correctly enforces that COSE_Sign1 must be a 4-element array (protected headers, unprotected headers, payload, signature).
28-46: LGTM! Proper issuer extraction and scheme handling.The method correctly extracts the issuer claim (CWT claim 1 per RFC 8392) and appropriately handles different URI schemes: DIDs are returned as-is, while HTTP(S) URIs are resolved to their JWKS endpoints.
67-76: LGTM! Correct CWT claims extraction.The method properly extracts the payload from the COSE_Sign1 structure (index 2) and validates that CWT claims form a CBOR map per RFC 8392.
78-93: LGTM! Signature verification logic is sound.The method correctly validates the COSE_Sign1 signature using the resolved public key. The safe cast at line 83-84 properly handles type mismatches.
...erifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt
Outdated
Show resolved
Hide resolved
...erifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt
Outdated
Show resolved
Hide resolved
Signed-off-by: jaswanthkumarpolisetty <jaswanthkumar.p@thoughtworks.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt (1)
76-100: Solid verification flow with correct exception handling.The main
verify()method implements a clean flow:
- Hex decode → CBOR decode → Structure validation
- Claims & issuer extraction
- Public key resolution via factory
- Signature verification
The exception handling at lines 90-98 is correct: specific exceptions (
PublicKeyNotFoundException,SignatureVerificationException) are propagated, while unexpected exceptions are wrapped inUnknownExceptionwith context. The static analysis warning about "SwallowedException" is a false positive—no exceptions are silently discarded.Minor consideration: Line 87 instantiates a new
PublicKeyResolverFactory()on every verification. If the factory is stateless, this is fine. If it has initialization overhead or caches, consider making it a class-level property.Based on learnings,
PublicKeyResolverFactory().get(issuer)throwsPublicKeyNotFoundExceptionwhen resolution fails (rather than returning null), so the current exception handling is appropriate.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
vc-verifier/kotlin/gradle/libs.versions.tomlvc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt
🚧 Files skipped from review as they are similar to previous changes (1)
- vc-verifier/kotlin/gradle/libs.versions.toml
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-01-07T10:57:30.150Z
Learnt from: jaswanthkumartw
Repo: inji/vc-verifier PR: 216
File: vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt:95-123
Timestamp: 2026-01-07T10:57:30.150Z
Learning: In the CwtVerifier class, the `PublicKeyResolverFactory().get(issuer)` method throws `PublicKeyNotFoundException` when a key cannot be resolved, rather than returning null.
Applied to files:
vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt
🪛 detekt (1.23.8)
vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt
[warning] 90-90: The caught exception is swallowed. The original exception could be lost.
(detekt.exceptions.SwallowedException)
🔇 Additional comments (4)
vc-verifier/kotlin/vcverifier/src/main/java/io/mosip/vercred/vcverifier/credentialverifier/verifier/CwtVerifier.kt (4)
22-26: LGTM! Correct COSE_Sign1 structure validation.The validation correctly checks that the COSE object is an array with exactly 4 elements (protected headers, unprotected headers, payload, and signature), per the COSE_Sign1 specification.
48-57: LGTM! Correct CWT claims extraction and validation.The method correctly extracts the payload from index 2 of the COSE_Sign1 array, decodes it as CBOR, and validates it's a map structure containing the CWT claims.
59-74: LGTM! Correct COSE signature verification.The signature verification correctly:
- Decodes and validates the COSE_Sign1 object structure
- Creates a COSEKey from the resolved public key (with
nullalgorithm parameter to infer from COSE headers)- Verifies the signature using the COSE library's
validate()method
28-46: The implementation correctly follows RFC 8615 standards for well-known resource resolution. UsingURI.resolve("/.well-known/jwks.json")with an absolute path is intentional—the JWKS endpoint should be at the domain root regardless of the issuer's path structure. For example,https://api.collab.mosip.net/tenant1correctly resolves tohttps://api.collab.mosip.net/.well-known/jwks.json, which is the expected behavior.Regarding the
URISyntaxExceptionat line 40: while an explicit catch with a more descriptive error message would be a minor improvement, the exception is already handled by the outer try-catch block at line 90 and converted toUnknownException, which is acceptable error handling.Likely an incorrect or invalid review comment.
Summary by CodeRabbit
New Features
Enhancements
Tests
Chores
✏️ Tip: You can customize this high-level summary in your review settings.