[OID4VCI] Fix c_nonce replay protection#50120
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes OID4VCI c_nonce replay protection by introducing explicit nonce consumption (single-use enforcement) after successful credential issuance, preventing replay of captured proof JWTs within the nonce validity window.
Changes:
- Adds
CNonceHandler.consumeCNonce()and implements it inJwtCNonceHandlerusingSingleUseObjectProvider.putIfAbsent()with TTL derived from remaining nonce validity plus clock skew. - Consumes distinct proof nonces once at the credential request boundary in
OID4VCIssuerEndpoint(while keepingverifyCNonce()side-effect free for multi-proof flows). - Removes prior (incorrect) attestation nonce replay handling and adds regression coverage for consumption semantics.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/base/src/test/java/org/keycloak/tests/oid4vc/NonceEndpointTest.java | Adds a regression test for single-use nonce consumption behavior (provider-level). |
| services/src/main/java/org/keycloak/protocol/oid4vc/issuance/OID4VCIssuerEndpoint.java | Consumes proof c_nonce values once per successful credential request to block replay. |
| services/src/main/java/org/keycloak/protocol/oid4vc/issuance/keybinding/JwtCNonceHandler.java | Implements single-use consumption via SingleUseObjectProvider with hashed key and TTL. |
| services/src/main/java/org/keycloak/protocol/oid4vc/issuance/keybinding/CNonceHandler.java | Introduces the consumeCNonce() API (default throws when unsupported). |
| services/src/main/java/org/keycloak/protocol/oid4vc/issuance/keybinding/AttestationProofValidator.java | Removes earlier attestation-specific replay handling to centralize consumption at request boundary. |
|
@forkimenjeckayang You mention, that the implementation is kept side-effect free, so that "multi-proof and key-attestation flows can validate the same nonce during one request". But this not actually tested right now? I guess this is about batch issuance and key attestation/proof sharing the same nonce? |
Good point. I added an explicit assertion for the key-attestation case now. The multi-proof case was already covered by For key attestation, |
4c6552c to
ce87986
Compare
24b5aeb to
5b505d5
Compare
5b505d5 to
c5ffa55
Compare
c5ffa55 to
58abbd7
Compare
Closes keycloak#48043 Signed-off-by: forkimenjeckayang <forkimenjeckayang@gmail.com> Signed-off-by: Ingrid Kamga <Ingrid.Kamga@adorsys.com>
c39897f to
122c972
Compare
mposolda
left a comment
There was a problem hiding this comment.
@forkimenjeckayang @Awambeng @dominikschlosser Thanks for this PR and for the reviews!
Fixes OID4VCI
c_noncereplay protection by marking verified proof nonces as consumed after successful credential request processing.The nonce is stored in
SingleUseObjectProviderusing a hashed key, with the cache lifetime calculated from the remaining nonce validity plus clock skew. This prevents a captured proof JWT from being replayed within the nonce validity window.Details
CNonceHandler.consumeCNonce()for explicit nonce consumption.JwtCNonceHandlerwithputIfAbsent().exp - now + clockSkew.verifyCNonce()side-effect free so multi-proof and key-attestation flows can validate the same nonce during one request.closes #48043