Skip to content

[OID4VCI] Harden key attestation x5c certificate validation#51042

Open
forkimenjeckayang wants to merge 4 commits into
keycloak:mainfrom
adorsys:issue-50518
Open

[OID4VCI] Harden key attestation x5c certificate validation#51042
forkimenjeckayang wants to merge 4 commits into
keycloak:mainfrom
adorsys:issue-50518

Conversation

@forkimenjeckayang

Copy link
Copy Markdown
Contributor

Summary

This change hardens validation of X.509 certificate chains supplied through the
x5c header of OID4VCI key attestations.

Previously, attestation chains were validated against the JVM system truststore,
which allowed certificates issued by general Web PKI certificate authorities.
Revocation checking was disabled and no Extended Key Usage policy was enforced.

The implementation now:

  • validates key-attestation chains only against dedicated trust anchors exposed
    by the trust-material identity providers configured for the OID4VCI client;
  • never uses the JVM system truststore as an attestation trust source;
  • requires configured trust anchors to be self-signed CA root certificates with
    certificate-signing usage;
  • requires the attestation signing certificate to be an end-entity certificate;
  • enforces administrator-configured attestation EKU OIDs;
  • enables PKIX revocation checking by default and fails closed when revocation
    information is unavailable;
  • keeps each configured trust provider as an independent trust domain;
  • preserves x5c as a key-conveyance mechanism for ordinary JWT proofs, where
    attestation trust validation does not apply;
  • adds Admin Console configuration and documentation for X.509 attestation
    trust.

closes #50518

Signed-off-by: forkimenjeckayang <forkimenjeckayang@gmail.com>
Copilot AI review requested due to automatic review settings July 20, 2026 14:23
@forkimenjeckayang
forkimenjeckayang requested review from a team as code owners July 20, 2026 14:23

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

Hardens OID4VCI key-attestation certificate validation by introducing dedicated X.509 trust material and policies.

Changes:

  • Adds isolated PKIX validation with EKU, end-entity, and revocation enforcement.
  • Adds trust-provider and Admin Console X.509 configuration.
  • Expands documentation and integration/UI tests.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/base/.../OID4VCKeyAttestationTest.java Tests attestation certificate policies.
services/.../X5cKeyUtils.java Decodes chains and converts leaf keys.
services/.../TrustedAttestationKeyResolver.java Resolves configured X.509 trust.
services/.../StaticAttestationKeyResolver.java Supports static X.509 trust material.
services/.../JwtProofValidator.java Preserves proof-key x5c conveyance.
services/.../AttestationX509CertificateValidator.java Implements PKIX policy validation.
services/.../AttestationValidatorUtil.java Removes system-truststore attestation validation.
services/.../AttestationKeyResolver.java Adds certificate-chain resolution API.
services/.../DefaultTrustIdentityProviderConfig.java Defines and validates X.509 settings.
services/.../DefaultTrustIdentityProvider.java Exposes X.509 trust material.
services/.../TrustMaterialResolver.java Resolves X.509 material by provider.
server-spi-private/.../X509TrustMaterial.java Models trust anchors and policy.
server-spi-private/.../TrustMaterialIdentityProvider.java Extends the trust-provider SPI.
js/.../default-trust.spec.ts Tests new Admin Console controls.
js/.../DefaultTrustSettings.tsx Adds X.509 configuration fields.
js/.../messages_en.properties Adds X.509 setting labels and help.
docs/.../proofs.adoc Documents attestation trust configuration.

@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.BrowserFlowTest#testUserWithOneAdditionalFactorOtpSuccess

Keycloak CI - Base IT (5)

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#multipleTabsParallelLoginTestWithAuthSessionExpiredAndRequiredAction

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.oauth.ClientAuthPostMethodTest#testPostAuthenticationNotAllowedWhenBasicRequested

Keycloak CI - Base IT (6)

java.lang.NullPointerException: Cannot read field "features" because the return value of "org.keycloak.common.Profile.getInstance()" is null
	at org.keycloak.common.Profile.isFeatureEnabled(Profile.java:534)
	at org.keycloak.protocol.oidc.OIDCClientSecretConfigWrapper.<init>(OIDCClientSecretConfigWrapper.java:41)
	at org.keycloak.protocol.oidc.OIDCClientSecretConfigWrapper.fromClientRepresentation(OIDCClientSecretConfigWrapper.java:49)
	at org.keycloak.testsuite.oauth.ClientAuthPostMethodTest.testPostAuthenticationNotAllowedWhenBasicRequested(ClientAuthPostMethodTest.java:141)
...

Report flaky test

org.keycloak.testsuite.oauth.ClientAuthPostMethodTest#testBasicAuthenticationNotAllowedWhenPostRequested

Keycloak CI - Base IT (6)

java.lang.NullPointerException: Cannot read field "features" because the return value of "org.keycloak.common.Profile.getInstance()" is null
	at org.keycloak.common.Profile.isFeatureEnabled(Profile.java:534)
	at org.keycloak.protocol.oidc.OIDCClientSecretConfigWrapper.<init>(OIDCClientSecretConfigWrapper.java:41)
	at org.keycloak.protocol.oidc.OIDCClientSecretConfigWrapper.fromClientRepresentation(OIDCClientSecretConfigWrapper.java:49)
	at org.keycloak.testsuite.oauth.ClientAuthPostMethodTest.testBasicAuthenticationNotAllowedWhenPostRequested(ClientAuthPostMethodTest.java:112)
...

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

org.keycloak.testsuite.forms.MultipleTabsLoginTest#multipleTabsParallelLoginTest

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)
...
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

Signed-off-by: forkimenjeckayang <forkimenjeckayang@gmail.com>

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 17 out of 17 changed files in this pull request and generated 2 comments.

Signed-off-by: forkimenjeckayang <forkimenjeckayang@gmail.com>
Copilot AI review requested due to automatic review settings July 21, 2026 07:50

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 17 out of 17 changed files in this pull request and generated 2 comments.

Signed-off-by: forkimenjeckayang <forkimenjeckayang@gmail.com>
Copilot AI review requested due to automatic review settings July 21, 2026 08:11

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 17 out of 17 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.BrowserFlowTest#testUserWithOneAdditionalFactorOtpSuccess

Keycloak CI - Base IT (5)

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#multipleTabsParallelLoginTestWithAuthSessionExpiredInTheMiddle

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#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

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.

OID4VCI: Key attestation x5c chain validated against system cacerts with no EKU or revocation

2 participants