From 43610cfa6732d34adc3b96a98c8a785e5afce90d Mon Sep 17 00:00:00 2001 From: forkimenjeckayang <104195313+forkimenjeckayang@users.noreply.github.com> Date: Fri, 1 Aug 2025 08:13:35 +0100 Subject: [PATCH] [OID4VCI] Update SD-JWT VCs Format Identifier to dc+sd-jwt (#41233) Closes #39293 Signed-off-by: forkimenjeckayang --- .../org/keycloak/sdjwt/IssuerSignedJWT.java | 2 +- .../keycloak/sdjwt/sdjwtvp/SdJwtVPTest.java | 6 ++-- .../resources/sdjwt/s3.3-unsecured-sd-jwt.txt | 29 +------------------ .../oid4vci/vc-issuer-configuration.adoc | 6 ++-- .../realms/verifiable-credentials-realm.json | 4 +-- .../models/oid4vci/CredentialScopeModel.java | 2 +- .../protocol/oid4vc/model/Format.java | 2 +- 7 files changed, 12 insertions(+), 39 deletions(-) diff --git a/core/src/main/java/org/keycloak/sdjwt/IssuerSignedJWT.java b/core/src/main/java/org/keycloak/sdjwt/IssuerSignedJWT.java index 250dafad58a..044180db7ba 100644 --- a/core/src/main/java/org/keycloak/sdjwt/IssuerSignedJWT.java +++ b/core/src/main/java/org/keycloak/sdjwt/IssuerSignedJWT.java @@ -225,7 +225,7 @@ public class IssuerSignedJWT extends SdJws { public IssuerSignedJWT build() { // Preinitialize hashAlg to sha-256 if not provided hashAlg = hashAlg == null ? "sha-256" : hashAlg; - jwsType = jwsType == null ? "vc+sd-jwt" : jwsType; + jwsType = jwsType == null ? "dc+sd-jwt" : jwsType; // send an empty lise if claims not set. claims = claims == null ? Collections.emptyList() : claims; decoyClaims = decoyClaims == null ? Collections.emptyList() : decoyClaims; diff --git a/core/src/test/java/org/keycloak/sdjwt/sdjwtvp/SdJwtVPTest.java b/core/src/test/java/org/keycloak/sdjwt/sdjwtvp/SdJwtVPTest.java index 2ae3488431c..6dab6631704 100644 --- a/core/src/test/java/org/keycloak/sdjwt/sdjwtvp/SdJwtVPTest.java +++ b/core/src/test/java/org/keycloak/sdjwt/sdjwtvp/SdJwtVPTest.java @@ -143,7 +143,7 @@ public abstract class SdJwtVPTest { @Test public void testS6_2_PresentationPositive() throws VerificationException { - String jwsType = "vc+sd-jwt"; + String jwsType = "dc+sd-jwt"; String sdJwtVPString = TestUtils.readFileAsString(getClass(), "sdjwt/s6.2-presented-sdjwtvp.txt"); SdJwtVP sdJwtVP = SdJwtVP.of(sdJwtVPString); JsonNode keyBindingClaims = TestUtils.readClaimSet(getClass(), "sdjwt/s6.2-key-binding-claims.json"); @@ -163,7 +163,7 @@ public abstract class SdJwtVPTest { @Test(expected = VerificationException.class) public void testS6_2_PresentationNegative() throws VerificationException { - String jwsType = "vc+sd-jwt"; + String jwsType = "dc+sd-jwt"; String sdJwtVPString = TestUtils.readFileAsString(getClass(), "sdjwt/s6.2-presented-sdjwtvp.txt"); SdJwtVP sdJwtVP = SdJwtVP.of(sdJwtVPString); JsonNode keyBindingClaims = TestUtils.readClaimSet(getClass(), "sdjwt/s6.2-key-binding-claims.json"); @@ -182,7 +182,7 @@ public abstract class SdJwtVPTest { @Test public void testS6_2_PresentationPartialDisclosure() throws VerificationException { - String jwsType = "vc+sd-jwt"; + String jwsType = "dc+sd-jwt"; String sdJwtVPString = TestUtils.readFileAsString(getClass(), "sdjwt/s6.2-presented-sdjwtvp.txt"); SdJwtVP sdJwtVP = SdJwtVP.of(sdJwtVPString); JsonNode keyBindingClaims = TestUtils.readClaimSet(getClass(), "sdjwt/s6.2-key-binding-claims.json"); diff --git a/core/src/test/resources/sdjwt/s3.3-unsecured-sd-jwt.txt b/core/src/test/resources/sdjwt/s3.3-unsecured-sd-jwt.txt index 94169248ea7..8c8128f7bc4 100644 --- a/core/src/test/resources/sdjwt/s3.3-unsecured-sd-jwt.txt +++ b/core/src/test/resources/sdjwt/s3.3-unsecured-sd-jwt.txt @@ -1,28 +1 @@ -eyJhbGciOiAiRVMyNTYiLCAia2lkIjogImRvYy1zaWduZXItMDUtMjUtMjAyMiIsICJ0 -eXAiOiAidmMrc2Qtand0In0.eyJfc2QiOiBbIjA5dktySk1PbHlUV00wc2pwdV9wZE9C -VkJRMk0xeTNLaHBINTE1blhrcFkiLCAiMnJzakdiYUMwa3k4bVQwcEpyUGlvV1RxMF9k -YXcxc1g3NnBvVWxnQ3diSSIsICJFa084ZGhXMGRIRUpidlVIbEVfVkNldUM5dVJFTE9p -ZUxaaGg3WGJVVHRBIiwgIklsRHpJS2VpWmREd3BxcEs2WmZieXBoRnZ6NUZnbldhLXNO -NndxUVhDaXciLCAiSnpZakg0c3ZsaUgwUjNQeUVNZmVadTZKdDY5dTVxZWhabzdGN0VQ -WWxTRSIsICJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJ -IiwgIlRHZjRvTGJnd2Q1SlFhSHlLVlFaVTlVZEdFMHc1cnREc3JaemZVYW9tTG8iLCAi -amRyVEU4WWNiWTRFaWZ1Z2loaUFlX0JQZWt4SlFaSUNlaVVRd1k5UXF4SSIsICJqc3U5 -eVZ1bHdRUWxoRmxNXzNKbHpNYVNGemdsaFFHMERwZmF5UXdMVUs0Il0sICJpc3MiOiAi -aHR0cHM6Ly9leGFtcGxlLmNvbS9pc3N1ZXIiLCAiaWF0IjogMTY4MzAwMDAwMCwgImV4 -cCI6IDE4ODMwMDAwMDAsICJ2Y3QiOiAiaHR0cHM6Ly9jcmVkZW50aWFscy5leGFtcGxl -LmNvbS9pZGVudGl0eV9jcmVkZW50aWFsIiwgIl9zZF9hbGciOiAic2hhLTI1NiIsICJj -bmYiOiB7Imp3ayI6IHsia3R5IjogIkVDIiwgImNydiI6ICJQLTI1NiIsICJ4IjogIlRD -QUVSMTladnUzT0hGNGo0VzR2ZlNWb0hJUDFJTGlsRGxzN3ZDZUdlbWMiLCAieSI6ICJa -eGppV1diWk1RR0hWV0tWUTRoYlNJaXJzVmZ1ZWNDRTZ0NGpUOUYySFpRIn19fQ.YHjaS -waBy-6hBYBre1F1ehiHNp69F9jnP2Hve3g0gNTzG_6GxV-E9rPR5m_CCo1SgDk0GaE5S -II6FBprkwDP-Q~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLC -AiSm9obiJd~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImZhbWlseV9uYW1lIiwgI -kRvZSJd~WyI2SWo3dE0tYTVpVlBHYm9TNXRtdlZBIiwgImVtYWlsIiwgImpvaG5kb2VA -ZXhhbXBsZS5jb20iXQ~WyJlSThaV205UW5LUHBOUGVOZW5IZGhRIiwgInBob25lX251b -WJlciIsICIrMS0yMDItNTU1LTAxMDEiXQ~WyJRZ19PNjR6cUF4ZTQxMmExMDhpcm9BIi -wgImFkZHJlc3MiLCB7InN0cmVldF9hZGRyZXNzIjogIjEyMyBNYWluIFN0IiwgImxvY2 -FsaXR5IjogIkFueXRvd24iLCAicmVnaW9uIjogIkFueXN0YXRlIiwgImNvdW50cnkiOi -AiVVMifV0~WyJBSngtMDk1VlBycFR0TjRRTU9xUk9BIiwgImJpcnRoZGF0ZSIsICIxOT -QwLTAxLTAxIl0~WyJQYzMzSk0yTGNoY1VfbEhnZ3ZfdWZRIiwgImlzX292ZXJfMTgiLC -B0cnVlXQ~WyJHMDJOU3JRZmpGWFE3SW8wOXN5YWpBIiwgImlzX292ZXJfMjEiLCB0cnV -lXQ~WyJsa2x4RjVqTVlsR1RQVW92TU5JdkNBIiwgImlzX292ZXJfNjUiLCB0cnVlXQ~ \ No newline at end of file +eyJhbGciOiJFUzI1NiIsInR5cCIgOiAiZGMrc2Qtand0Iiwia2lkIiA6ICJkb2Mtc2lnbmVyLTA1LTI1LTIwMjIifQ.eyJfc2QiOlsiMDl2S3JKTU9seVRXTTBzanB1X3BkT0JWQlEyTTF5M0tocEg1MTVuWGtwWSIsIjJyc2pHYmFDMGt5OG1UMHBKclBpb1dUcTBfZGF3MXNYNzZwb1VsZ0N3YkkiLCJFa084ZGhXMGRIRUpidlVIbEVfVkNldUM5dVJFTE9pZUxaaGg3WGJVVHRBIiwiSWxEeklLZWlaZER3cHFwSzZaZmJ5cGhGdno1RmduV2Etc042d3FRWENpdyIsIkp6WWpINHN2bGlIMFIzUHlFTWZlWnU2SnQ2OXU1cWVoWm83RjdFUFlsU0UiLCJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJIiwiVEdmNG9MYmd3ZDVKUWFIeUtWUVpVOVVkR0UwdzVydERzclp6ZlVhb21MbyIsImpkclRFOFljYlk0RWlmdWdpaGlBZV9CUGVreEpRWklDZWlVUXdZOVFxeEkiLCJqc3U5eVZ1bHdRUWxoRmxNXzNKbHpNYVNGemdsaFFHMERwZmF5UXdMVUs0Il0sIl9zZF9hbGciOiJzaGEtMjU2IiwidmN0IjoiaHR0cHM6Ly9jcmVkZW50aWFscy5leGFtcGxlLmNvbS9pZGVudGl0eV9jcmVkZW50aWFsIiwiaXNzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9pc3N1ZXIiLCJpYXQiOjE2ODMwMDAwMDAsImV4cCI6MTg4MzAwMDAwMCwiY25mIjp7Imp3ayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2IiwieCI6IlRDQUVSMTladnUzT0hGNGo0VzR2ZlNWb0hJUDFJTGlsRGxzN3ZDZUdlbWMiLCJ5IjoiWnhqaVdXYlpNUUdIVldLVlE0aGJTSWlyc1ZmdWVjQ0U2dDRqVDlGMkhaUSJ9fX0.u391JMPx4kCneuNkKY9AkLumpw7rbapm3r2UqiRqMW6h_9Y_yGCkBbJ_BeccpIg2zQzWOti3r_pLztx9WfB2dw~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImZhbWlseV9uYW1lIiwgIkRvZSJd~WyI2SWo3dE0tYTVpVlBHYm9TNXRtdlZBIiwgImVtYWlsIiwgImpvaG5kb2VAZXhhbXBsZS5jb20iXQ~WyJlSThaV205UW5LUHBOUGVOZW5IZGhRIiwgInBob25lX251bWJlciIsICIrMS0yMDItNTU1LTAxMDEiXQ~WyJRZ19PNjR6cUF4ZTQxMmExMDhpcm9BIiwgImFkZHJlc3MiLCB7InN0cmVldF9hZGRyZXNzIjogIjEyMyBNYWluIFN0IiwgImxvY2FsaXR5IjogIkFueXRvd24iLCAicmVnaW9uIjogIkFueXN0YXRlIiwgImNvdW50cnkiOiAiVVMifV0~WyJBSngtMDk1VlBycFR0TjRRTU9xUk9BIiwgImJpcnRoZGF0ZSIsICIxOTQwLTAxLTAxIl0~WyJQYzMzSk0yTGNoY1VfbEhnZ3ZfdWZRIiwgImlzX292ZXJfMTgiLCB0cnVlXQ~WyJHMDJOU3JRZmpGWFE3SW8wOXN5YWpBIiwgImlzX292ZXJfMjEiLCB0cnVlXQ~WyJsa2x4RjVqTVlsR1RQVW92TU5JdkNBIiwgImlzX292ZXJfNjUiLCB0cnVlXQ~ \ No newline at end of file diff --git a/docs/documentation/server_admin/topics/oid4vci/vc-issuer-configuration.adoc b/docs/documentation/server_admin/topics/oid4vci/vc-issuer-configuration.adoc index de285d885ea..ca4ea158668 100644 --- a/docs/documentation/server_admin/topics/oid4vci/vc-issuer-configuration.adoc +++ b/docs/documentation/server_admin/topics/oid4vci/vc-issuer-configuration.adoc @@ -284,7 +284,7 @@ _Default_: `$\{name}+` | `vc.format` | optional | Defines the VC format (e.g., `jwt_vc`). + -_Default_: `vc+sd-jwt` +_Default_: `dc+sd-jwt` | `vc.verifiable_credential_type` | optional @@ -323,12 +323,12 @@ _Default_: _none_ | `vc.sd_jwt.number_of_decoys` | optional -| Used only with format `vc+sd-jwt`. Number of decoy hashes in the SD-JWT. + +| Used only with format `dc+sd-jwt`. Number of decoy hashes in the SD-JWT. + _Default_: `10` | `vc.credential_build_config.sd_jwt.visible_claims` | optional -| Used only with format `vc+sd-jwt`. Claims always disclosed in the SD-JWT body. + +| Used only with format `dc+sd-jwt`. Claims always disclosed in the SD-JWT body. + _Default_: `id,iat,nbf,exp,jti` | `vc.credential_build_config.hash_algorithm` diff --git a/js/apps/account-ui/test/realms/verifiable-credentials-realm.json b/js/apps/account-ui/test/realms/verifiable-credentials-realm.json index b30e18d1b45..78beadd15ad 100644 --- a/js/apps/account-ui/test/realms/verifiable-credentials-realm.json +++ b/js/apps/account-ui/test/realms/verifiable-credentials-realm.json @@ -185,8 +185,8 @@ "org.keycloak.protocol.oid4vc.issuance.credentialbuilder.CredentialBuilder": [ { "id": "sd-jwt-credential-builder", - "name": "credential-builder-vc+sd-jwt", - "providerId": "vc+sd-jwt", + "name": "credential-builder-dc+sd-jwt", + "providerId": "dc+sd-jwt", "subComponents": {}, "config": {} } diff --git a/server-spi-private/src/main/java/org/keycloak/models/oid4vci/CredentialScopeModel.java b/server-spi-private/src/main/java/org/keycloak/models/oid4vci/CredentialScopeModel.java index 1dd68ce5697..756a5d0ca06 100644 --- a/server-spi-private/src/main/java/org/keycloak/models/oid4vci/CredentialScopeModel.java +++ b/server-spi-private/src/main/java/org/keycloak/models/oid4vci/CredentialScopeModel.java @@ -44,7 +44,7 @@ public class CredentialScopeModel implements ClientScopeModel { public static final String SD_JWT_VISIBLE_CLAIMS_DEFAULT = "id,iat,nbf,exp,jti"; public static final int SD_JWT_DECOYS_DEFAULT = 10; - public static final String FORMAT_DEFAULT = "vc+sd-jwt"; + public static final String FORMAT_DEFAULT = "dc+sd-jwt"; public static final String HASH_ALGORITHM_DEFAULT = "SHA-256"; public static final String TOKEN_TYPE_DEFAULT = "JWS"; public static final int EXPIRY_IN_SECONDS_DEFAULT = 31536000; diff --git a/services/src/main/java/org/keycloak/protocol/oid4vc/model/Format.java b/services/src/main/java/org/keycloak/protocol/oid4vc/model/Format.java index 02ec709c353..7febb65322c 100644 --- a/services/src/main/java/org/keycloak/protocol/oid4vc/model/Format.java +++ b/services/src/main/java/org/keycloak/protocol/oid4vc/model/Format.java @@ -40,7 +40,7 @@ public class Format { /** * SD-JWT-Credentials {@see https://drafts.oauth.net/oauth-sd-jwt-vc/draft-ietf-oauth-sd-jwt-vc.html} */ - public static final String SD_JWT_VC = "vc+sd-jwt"; + public static final String SD_JWT_VC = "dc+sd-jwt"; public static final Set SUPPORTED_FORMATS = Collections.unmodifiableSet(Set.of(JWT_VC, LDP_VC, SD_JWT_VC)); }