Skip to content

[OID4VCI]: Fix JWT proof JWK claim type confusion causing proof validation failure#50822

Open
Awambeng wants to merge 2 commits into
keycloak:mainfrom
adorsys:issue-50749
Open

[OID4VCI]: Fix JWT proof JWK claim type confusion causing proof validation failure#50822
Awambeng wants to merge 2 commits into
keycloak:mainfrom
adorsys:issue-50749

Conversation

@Awambeng

@Awambeng Awambeng commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Issue

  • An attacker-supplied JWT proof containing "crv": [] (an array instead of a string) in the JOSE header jwk field could trigger an unhandled ClassCastException in AbstractProofValidator.getKeyWrapper(), resulting in a 500 Internal Server Error instead of the expected invalid_proof response.

Root cause

  • JWK.getOtherClaim("crv", String.class) internally calls String.class.cast(ArrayList), which throws a ClassCastException when the claim has an unexpected type. This exception was not handled by JwtProofValidator.validateProof(), whose catch block only handled JWSInputException, VerificationException, and IOException.

Fix

  • Fix 1 – JWK.getOtherClaim() (root cause): Now catches ClassCastException and returns null. A type mismatch is treated the same as a missing claim, matching the method's contract. This provides a systemic fix for all callers, including AbstractProofValidator, JWKSUtils, and EdECUtilsImpl.
  • Fix 2 – AbstractProofValidator.getKeyWrapper() (defense in depth): Wraps JWKParser.toPublicKey() in a try-catch(RuntimeException) and rethrows a VerificationException. This ensures malformed JWKs (for example, missing kty or required EC fields) follow the existing INVALID_PROOF error path instead of propagating unchecked exceptions.

Why not catch RuntimeException?

  • Broadly catching RuntimeException in JwtProofValidator was intentionally avoided because VCIssuerException extends RuntimeException. Doing so would incorrectly convert issuer-specific errors (for example, INVALID_NONCE) into generic INVALID_PROOF responses.

Tests

  • JWKOtherClaimTest: 5 unit tests covering valid retrieval, absent claim, wrong type returning null, null value, and correct type retrieval.
  • OID4VCJWTIssuerEndpointTest.testRequestCredentialWithMalformedJwkCrvRejected(): Integration test verifying that a malformed "crv": [] JWT proof returns 400 INVALID_PROOF instead of causing an internal server error.

Closes #50749

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates JWK claim handling to avoid type-confusion casts during OID4VCI proof validation.

Changes:

  • Returns null for mismatched JWK claim types.
  • Adds unit and OID4VCI regression tests.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
core/src/main/java/org/keycloak/jose/jwk/JWK.java Handles claim type mismatches.
core/src/test/java/org/keycloak/jose/jwk/JWKOtherClaimTest.java Tests typed claim retrieval.
services/src/test/java/org/keycloak/protocol/oid4vc/issuance/keybinding/JwtProofValidatorTest.java Adds malformed-proof coverage.

Comment thread core/src/main/java/org/keycloak/jose/jwk/JWK.java
Copilot AI review requested due to automatic review settings July 13, 2026 11:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings July 13, 2026 11:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings July 21, 2026 08:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

@keycloak-github-bot

Copy link
Copy Markdown

Unreported flaky test detected

If the flaky tests below are affected by the changes, please review and update the changes accordingly. Otherwise, a maintainer should report the flaky tests prior to merging the PR.

org.keycloak.testsuite.forms.MultipleTabsLoginTest#multipleTabsParallelLoginTestWithAuthSessionExpiredAndRefreshInTab1

Keycloak CI - Forms IT (chrome)

org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
	at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
	at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
	at org.junit.jupiter.api.AssertTrue.failNotTrue(AssertTrue.java:63)
	at org.junit.jupiter.api.AssertTrue.assertTrue(AssertTrue.java:36)
...

Report flaky test

org.keycloak.testsuite.forms.MultipleTabsLoginTest#testEmptyBaseUrl

Keycloak CI - Forms IT (firefox)

org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
	at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
	at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
	at org.junit.jupiter.api.AssertTrue.failNotTrue(AssertTrue.java:63)
	at org.junit.jupiter.api.AssertTrue.assertTrue(AssertTrue.java:36)
...

Report flaky test

@keycloak-github-bot keycloak-github-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unreported flaky test detected, please review

Copilot AI review requested due to automatic review settings July 22, 2026 10:18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

@keycloak-github-bot keycloak-github-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unreported flaky test detected, please review

@keycloak-github-bot

Copy link
Copy Markdown

Unreported flaky test detected

If the flaky tests below are affected by the changes, please review and update the changes accordingly. Otherwise, a maintainer should report the flaky tests prior to merging the PR.

org.keycloak.testsuite.forms.MultipleTabsLoginTest#multipleTabsParallelLoginTestWithAuthSessionExpiredAndRegisterClick

Keycloak CI - Forms IT (chrome)

org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
	at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
	at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
	at org.junit.jupiter.api.AssertTrue.failNotTrue(AssertTrue.java:63)
	at org.junit.jupiter.api.AssertTrue.assertTrue(AssertTrue.java:36)
...

Report flaky test

org.keycloak.testsuite.forms.MultipleTabsLoginTest#testEmptyBaseUrl

Keycloak CI - Forms IT (firefox)

org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
	at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
	at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
	at org.junit.jupiter.api.AssertTrue.failNotTrue(AssertTrue.java:63)
	at org.junit.jupiter.api.AssertTrue.assertTrue(AssertTrue.java:36)
...

Report flaky test

Awambeng added 2 commits July 27, 2026 10:21
- Make JWK.getOtherClaim() type-safe by catching ClassCastException and returning null on type mismatch
- Add JWKOtherClaimTest with 5 tests verifying type-safe getOtherClaim behavior
- Add regression test in JwtProofValidatorTest for malformed JWK crv in proof header

Closes keycloak#50749

Signed-off-by: Awambeng Rodrick <awambengrodrick@gmail.com>
Signed-off-by: Awambeng Rodrick <awambengrodrick@gmail.com>
Copilot AI review requested due to automatic review settings July 27, 2026 09:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OID4VC JWT proof JWK claim type confusion crashes proof validation

2 participants