Skip to content

Commit

Permalink
add sd
Browse files Browse the repository at this point in the history
  • Loading branch information
wistefan committed Dec 14, 2023
1 parent 0ae5e54 commit 445c7bd
Show file tree
Hide file tree
Showing 25 changed files with 629 additions and 180 deletions.
5 changes: 2 additions & 3 deletions services/src/api/oidc4vci-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -246,11 +246,10 @@ components:
Format:
type: string
enum:
- "jwt_vc_json"
- "jwt_vc_json-ld"
- "ldp_vc"
- "jwt_vc"
example: "jwt_vc_json-ld"
- "sd-jwt_vc"
example: "sd-jwt_vc"
CredentialRequest:
type: object
properties:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,8 @@
import org.keycloak.protocol.oidc4vp.model.PreAuthorized;
import org.keycloak.protocol.oidc4vp.model.PreAuthorizedGrant;
import org.keycloak.protocol.oidc4vp.model.SupportedCredential;
import org.keycloak.protocol.oidc4vp.signing.FileBasedKeyLoader;
import org.keycloak.protocol.oidc4vp.signing.JWTSigningService;
import org.keycloak.protocol.oidc4vp.signing.LDSigningService;
import org.keycloak.protocol.oidc4vp.signing.SigningServiceException;
import org.keycloak.protocol.oidc4vp.model.vcdm.LdProof;
import org.keycloak.protocol.oidc4vp.signing.*;
import org.keycloak.representations.JsonWebToken;
import org.keycloak.services.managers.AppAuthManager;
import org.keycloak.services.managers.AuthenticationManager;
Expand Down Expand Up @@ -66,16 +64,19 @@ public class OIDC4VPIssuerEndpoint {

private final boolean ldSigningEnabled;
private final boolean jwtSigningEnabled;
private final boolean sdJwtSigningEnabled;
private LDSigningService ldSigningService;
private JWTSigningService jwtSigningService;
private JwtSigningService jwtSigningService;
private SdJwtSigningService sdJwtSigningService;

public OIDC4VPIssuerEndpoint(KeycloakSession session,
String issuerDid,
String keyPath,
Optional<String> jwtType,
Optional<String> ldpType,
Optional<String> sdJwtType,
AppAuthManager.BearerTokenAuthenticator authenticator,
ObjectMapper objectMapper, Clock clock) {
ObjectMapper objectMapper, Clock clock, Integer decoys, Optional<String> keyId) {
this.session = session;
this.bearerTokenAuthenticator = authenticator;
this.objectMapper = objectMapper;
Expand All @@ -84,7 +85,11 @@ public OIDC4VPIssuerEndpoint(KeycloakSession session,
var tempJwtSigningEnabled = false;
if (jwtType.isPresent()) {
try {
this.jwtSigningService = new JWTSigningService(new FileBasedKeyLoader(keyPath), Optional.empty(), clock, jwtType.get());
this.jwtSigningService = new JwtSigningService(
new FileBasedKeyLoader(keyPath),
keyId,
clock,
jwtType.get());
tempJwtSigningEnabled = true;
} catch (SigningServiceException e) {
LOGGER.warn("Was not able to initialize JWT SigningService, jwt credentials are not supported.", e);
Expand All @@ -96,7 +101,12 @@ public OIDC4VPIssuerEndpoint(KeycloakSession session,
var tempLdSigningEnabled = false;
if (ldpType.isPresent()) {
try {
this.ldSigningService = new LDSigningService(new FileBasedKeyLoader(keyPath), Optional.empty(), clock, ldpType.get(), objectMapper);
this.ldSigningService = new LDSigningService(
new FileBasedKeyLoader(keyPath),
keyId,
clock,
ldpType.get(),
objectMapper);
tempLdSigningEnabled = true;
} catch (SigningServiceException e) {
LOGGER.warn("Was not able to initialize LD SigningService, ld credentials are not supported.", e);
Expand All @@ -105,6 +115,25 @@ public OIDC4VPIssuerEndpoint(KeycloakSession session,
}
}
this.ldSigningEnabled = tempLdSigningEnabled;

var tempSdJWTSigningEnabled = false;
if (ldpType.isPresent()) {
try {
this.sdJwtSigningService = new SdJwtSigningService(
new FileBasedKeyLoader(keyPath),
keyId,
clock,
sdJwtType.get(),
objectMapper,
decoys);
tempSdJWTSigningEnabled = true;
} catch (SigningServiceException e) {
LOGGER.warn("Was not able to initialize SD-JWT SigningService, sd-jwt credentials are not supported.", e);
throw new IllegalArgumentException("No valid sd-jwt signing configured.", e);

}
}
this.sdJwtSigningEnabled = tempSdJWTSigningEnabled;
}

/**
Expand Down Expand Up @@ -264,10 +293,7 @@ public Response requestCredential(
// Optional.ofNullable(credentialRequestVO.getProof()).ifPresent(this::verifyProof);

Format requestedFormat = credentialRequestVO.getFormat();
// workaround to support implementations not differentiating json & json-ld
if (requestedFormat == JWT_VC) {
requestedFormat = JWT_VC_JSON;
}

// TODO: check if there can be more
String vcType = types.get(0);

Expand All @@ -277,8 +303,7 @@ public Response requestCredential(

Object theCredential = getCredential(vcType, credentialRequestVO.getFormat());
switch (requestedFormat) {
case LDP_VC -> responseVO.setCredential(theCredential);
case JWT_VC_JSON -> responseVO.setCredential(theCredential);
case LDP_VC, JWT_VC, SD_JWT_VC -> responseVO.setCredential(theCredential);
default -> throw new BadRequestException(
getErrorResponse(ErrorResponse.ErrorEnum.UNSUPPORTED_CREDENTIAL_TYPE));
}
Expand Down Expand Up @@ -324,13 +349,20 @@ protected Object getCredential(String vcType, Format format) {
throw new IllegalArgumentException(
String.format("Requested format %s is not supported.", format));
}
case JWT_VC, JWT_VC_JSON_LD, JWT_VC_JSON -> {
case JWT_VC -> {
if (jwtSigningEnabled) {
yield jwtSigningService.signCredential(credentialToSign);
}
throw new IllegalArgumentException(
String.format("Requested format %s is not supported.", format));
}
case SD_JWT_VC -> {
if (sdJwtSigningEnabled) {
yield sdJwtSigningService.signCredential(credentialToSign);
}
throw new IllegalArgumentException(
String.format("Requested format %s is not supported.", format));
}
};
}

Expand Down Expand Up @@ -384,8 +416,8 @@ private List<ClientModel> getClientsOfType(String vcType, Format format) {

List<String> formatStrings = switch (format) {
case LDP_VC -> List.of(LDP_VC.toString());
case JWT_VC, JWT_VC_JSON -> List.of(JWT_VC.toString(), JWT_VC_JSON.toString());
case JWT_VC_JSON_LD -> List.of(JWT_VC.toString(), JWT_VC_JSON_LD.toString());
case JWT_VC -> List.of(JWT_VC.toString());
case SD_JWT_VC -> List.of(SD_JWT_VC.toString());

};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,18 @@ public Object createProtocolEndpoint(KeycloakSession keycloakSession, EventBuild
.orElseThrow(() -> new VCIssuerException("No keyPath configured."));
Optional<String> lpdType = Optional.ofNullable(keycloakSession.getContext().getRealm().getAttribute("ldpType"));
Optional<String> jwtType = Optional.ofNullable(keycloakSession.getContext().getRealm().getAttribute("jwtType"));
Optional<String> sdJwtType = Optional.ofNullable(keycloakSession.getContext().getRealm().getAttribute("sdJwtType"));

Integer decoys = Optional.ofNullable(keycloakSession.getContext().getRealm().getAttribute("decoys")).map(Integer::valueOf).orElse(0);
Optional<String> keyId = Optional.ofNullable(keycloakSession.getContext().getRealm().getAttribute("keyId"));
return new OIDC4VPIssuerEndpoint(
keycloakSession,
issuerDid, keyPath,
jwtType, lpdType,
jwtType, sdJwtType, lpdType,
new AppAuthManager.BearerTokenAuthenticator(
keycloakSession),
OBJECT_MAPPER,
clock
OBJECT_MAPPER, clock,
decoys, keyId
);
}

Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.keycloak.protocol.oidc4vp.model;

import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.DatabindException;
import org.keycloak.protocol.oidc4vp.model.vcdm.LdProof;

import java.net.URI;
import java.util.Date;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.keycloak.protocol.oidc4vp.model.sdjwt;

import com.fasterxml.jackson.annotation.JsonProperty;

public class ArrayDigest {

@JsonProperty("...")
private String digest;

public ArrayDigest() {
}

public ArrayDigest(String digest) {
this.digest = digest;
}

public String getDigest() {
return digest;
}

public void setDigest(String digest) {
this.digest = digest;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.keycloak.protocol.oidc4vp.model.sdjwt;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;

import java.util.ArrayList;
import java.util.List;

public class ArrayDisclosureClaim {

private String key;
private List<ArrayElement> values = new ArrayList<>();

public ArrayDisclosureClaim() {
}

public ArrayDisclosureClaim(String key) {
this.key = key;
}

public String getKey() {
return key;
}

public void setKey(String key) {
this.key = key;
}

public List<ArrayElement> getValues() {
return values;
}

public void setValues(List<ArrayElement> values) {
this.values = values;
}

public void addValue(ArrayElement value) {
this.values.add(value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package org.keycloak.protocol.oidc4vp.model.sdjwt;

import java.util.Map;

public class ArrayElement {

private String disclosure;
private String digest;
private String salt;
private Object value;

public ArrayElement(String salt, Object value) {
this.salt = salt;
this.value = value;
}

public String getSalt() {
return salt;
}

public void setSalt(String salt) {
this.salt = salt;
}

public Object getValue() {
return value;
}

public void setValue(Object value) {
this.value = value;
}

public String getDisclosure() {
return disclosure;
}

public void setDisclosure(String disclosure) {
this.disclosure = disclosure;
}

public String getDigest() {
return digest;
}

public void setDigest(String digest) {
this.digest = digest;
}

public ArrayDigest asDigest() {
return new ArrayDigest(this.digest);
}
}
Loading

0 comments on commit 445c7bd

Please sign in to comment.