Skip to content

Instantly share code, notes, and snippets.

@andresrosenthal
Created July 18, 2024 13:54
Show Gist options
  • Save andresrosenthal/0f833f71b6d33805c20dca03c9e45796 to your computer and use it in GitHub Desktop.
Save andresrosenthal/0f833f71b6d33805c20dca03c9e45796 to your computer and use it in GitHub Desktop.
Extensible JWSSigner
diff --git core/identity-hub-core/src/main/java/org/eclipse/edc/identityhub/core/CoreServicesExtension.java core/identity-hub-core/src/main/java/org/eclipse/edc/identityhub/core/CoreServicesExtension.java
index e8d9f43..7ba49ed 100644
--- core/identity-hub-core/src/main/java/org/eclipse/edc/identityhub/core/CoreServicesExtension.java
+++ core/identity-hub-core/src/main/java/org/eclipse/edc/identityhub/core/CoreServicesExtension.java
@@ -14,6 +14,7 @@
package org.eclipse.edc.identityhub.core;
+import com.nimbusds.jose.JWSSigner;
import org.eclipse.edc.iam.did.spi.resolution.DidPublicKeyResolver;
import org.eclipse.edc.iam.identitytrust.spi.verification.SignatureSuiteRegistry;
import org.eclipse.edc.iam.verifiablecredentials.spi.RevocationListService;
@@ -41,7 +42,6 @@ import org.eclipse.edc.jsonld.spi.JsonLd;
import org.eclipse.edc.jsonld.util.JacksonJsonLd;
import org.eclipse.edc.keys.spi.KeyParserRegistry;
import org.eclipse.edc.keys.spi.LocalPublicKeyService;
-import org.eclipse.edc.keys.spi.PrivateKeyResolver;
import org.eclipse.edc.runtime.metamodel.annotation.Extension;
import org.eclipse.edc.runtime.metamodel.annotation.Inject;
import org.eclipse.edc.runtime.metamodel.annotation.Provider;
@@ -57,6 +57,7 @@ import org.eclipse.edc.verifiablecredentials.linkeddata.LdpIssuer;
import java.net.URISyntaxException;
import java.time.Clock;
+import java.util.function.Function;
import static org.eclipse.edc.iam.identitytrust.spi.DcpConstants.DCP_CONTEXT_URL;
import static org.eclipse.edc.identityhub.core.CoreServicesExtension.NAME;
@@ -92,7 +93,7 @@ public class CoreServicesExtension implements ServiceExtension {
@Inject
private ScopeToCriterionTransformer transformer;
@Inject
- private PrivateKeyResolver privateKeyResolver;
+ private Function<String, JWSSigner> jwsSignerResolver;
@Inject
private Clock clock;
@Inject
@@ -148,10 +149,10 @@ public class CoreServicesExtension implements ServiceExtension {
public PresentationCreatorRegistry presentationCreatorRegistry(ServiceExtensionContext context) {
if (presentationCreatorRegistry == null) {
presentationCreatorRegistry = new PresentationCreatorRegistryImpl(keyPairService, participantContextService);
- presentationCreatorRegistry.addCreator(new JwtPresentationGenerator(privateKeyResolver, clock, new JwtGenerationService()), CredentialFormat.JWT);
+ presentationCreatorRegistry.addCreator(new JwtPresentationGenerator(jwsSignerResolver, clock, new JwtGenerationService()), CredentialFormat.JWT);
var ldpIssuer = LdpIssuer.Builder.newInstance().jsonLd(jsonLd).monitor(context.getMonitor()).build();
- presentationCreatorRegistry.addCreator(new LdpPresentationGenerator(privateKeyResolver, signatureSuiteRegistry, IdentityHubConstants.JWS_2020_SIGNATURE_SUITE, ldpIssuer, typeManager.getMapper(JSON_LD)),
+ presentationCreatorRegistry.addCreator(new LdpPresentationGenerator(jwsSignerResolver, signatureSuiteRegistry, IdentityHubConstants.JWS_2020_SIGNATURE_SUITE, ldpIssuer, typeManager.getMapper(JSON_LD)),
CredentialFormat.JSON_LD);
}
return presentationCreatorRegistry;
diff --git core/lib/verifiable-presentation-lib/src/main/java/org/eclipse/edc/identithub/verifiablepresentation/generators/JwtPresentationGenerator.java core/lib/verifiable-presentation-lib/src/main/java/org/eclipse/edc/identithub/verifiablepresentation/generators/JwtPresentationGenerator.java
index 1eb8896..b6d1a0f 100644
--- core/lib/verifiable-presentation-lib/src/main/java/org/eclipse/edc/identithub/verifiablepresentation/generators/JwtPresentationGenerator.java
+++ core/lib/verifiable-presentation-lib/src/main/java/org/eclipse/edc/identithub/verifiablepresentation/generators/JwtPresentationGenerator.java
@@ -14,27 +14,26 @@
package org.eclipse.edc.identithub.verifiablepresentation.generators;
+import com.nimbusds.jose.JWSSigner;
import org.eclipse.edc.iam.identitytrust.spi.DcpConstants;
import org.eclipse.edc.iam.verifiablecredentials.spi.VcConstants;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.VerifiableCredentialContainer;
import org.eclipse.edc.identityhub.spi.verifiablecredentials.generator.PresentationGenerator;
import org.eclipse.edc.jsonld.spi.JsonLdKeywords;
import org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames;
-import org.eclipse.edc.keys.spi.PrivateKeyResolver;
import org.eclipse.edc.spi.EdcException;
import org.eclipse.edc.spi.iam.TokenRepresentation;
import org.eclipse.edc.token.spi.KeyIdDecorator;
import org.eclipse.edc.token.spi.TokenDecorator;
import org.eclipse.edc.token.spi.TokenGenerationService;
-import java.security.PrivateKey;
import java.time.Clock;
import java.time.Instant;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
-import java.util.function.Supplier;
+import java.util.function.Function;
import java.util.stream.Collectors;
import static org.eclipse.edc.identithub.verifiablepresentation.generators.PresentationGeneratorConstants.CONTROLLER_ADDITIONAL_DATA;
@@ -47,7 +46,7 @@ import static org.eclipse.edc.identithub.verifiablepresentation.generators.Prese
*/
public class JwtPresentationGenerator implements PresentationGenerator<String> {
public static final String VERIFIABLE_PRESENTATION_CLAIM = "vp";
- private final PrivateKeyResolver privateKeyResolver;
+ private final Function<String, JWSSigner> jwsSignerResolver;
private final Clock clock;
private final TokenGenerationService tokenGenerationService;
@@ -55,11 +54,11 @@ public class JwtPresentationGenerator implements PresentationGenerator<String> {
/**
* Creates a JWT presentation based on a list of Verifiable Credential Containers.
*
- * @param privateKeyResolver The resolver for private keys used for signing the presentation.
+ * @param jwsSignerResolver The resolver used for signing the presentation.
* @param clock The clock used for generating timestamps.
*/
- public JwtPresentationGenerator(PrivateKeyResolver privateKeyResolver, Clock clock, TokenGenerationService tokenGenerationService) {
- this.privateKeyResolver = privateKeyResolver;
+ public JwtPresentationGenerator(Function<String, JWSSigner> jwsSignerResolver, Clock clock, TokenGenerationService tokenGenerationService) {
+ this.jwsSignerResolver = jwsSignerResolver;
this.clock = clock;
this.tokenGenerationService = tokenGenerationService;
}
@@ -107,8 +106,8 @@ public class JwtPresentationGenerator implements PresentationGenerator<String> {
var rawVcs = credentials.stream()
.map(VerifiableCredentialContainer::rawVc)
.collect(Collectors.toList());
- Supplier<PrivateKey> privateKeySupplier = () -> privateKeyResolver.resolvePrivateKey(privateKeyAlias).orElseThrow(f -> new IllegalArgumentException(f.getFailureDetail()));
- var tokenResult = tokenGenerationService.generate(privateKeySupplier, vpDecorator(rawVcs, issuerId), tp -> {
+ JWSSigner jwsSigner = jwsSignerResolver.apply(privateKeyAlias);
+ var tokenResult = tokenGenerationService.generate(jwsSigner, vpDecorator(rawVcs, issuerId), tp -> {
additionalData.forEach(tp::claims);
return tp;
}, new KeyIdDecorator(composedKeyId));
diff --git core/lib/verifiable-presentation-lib/src/main/java/org/eclipse/edc/identithub/verifiablepresentation/generators/LdpPresentationGenerator.java core/lib/verifiable-presentation-lib/src/main/java/org/eclipse/edc/identithub/verifiablepresentation/generators/LdpPresentationGenerator.java
index c59db4a..49ac2a8 100644
--- core/lib/verifiable-presentation-lib/src/main/java/org/eclipse/edc/identithub/verifiablepresentation/generators/LdpPresentationGenerator.java
+++ core/lib/verifiable-presentation-lib/src/main/java/org/eclipse/edc/identithub/verifiablepresentation/generators/LdpPresentationGenerator.java
@@ -14,9 +14,11 @@
package org.eclipse.edc.identithub.verifiablepresentation.generators;
+import com.apicatalog.ld.signature.key.KeyPair;
import com.apicatalog.vc.suite.SignatureSuite;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.nimbusds.jose.JWSSigner;
import jakarta.json.Json;
import jakarta.json.JsonArray;
import jakarta.json.JsonArrayBuilder;
@@ -28,22 +30,19 @@ import org.eclipse.edc.iam.verifiablecredentials.spi.model.CredentialFormat;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.VerifiableCredentialContainer;
import org.eclipse.edc.identityhub.spi.verifiablecredentials.generator.PresentationGenerator;
import org.eclipse.edc.jsonld.spi.JsonLdKeywords;
-import org.eclipse.edc.keys.spi.PrivateKeyResolver;
import org.eclipse.edc.security.signature.jws2020.JsonWebKeyPair;
import org.eclipse.edc.security.signature.jws2020.Jws2020ProofDraft;
-import org.eclipse.edc.security.token.jwt.CryptoConverter;
import org.eclipse.edc.spi.EdcException;
import org.eclipse.edc.verifiablecredentials.linkeddata.LdpIssuer;
import org.jetbrains.annotations.NotNull;
import java.net.URI;
-import java.security.KeyPair;
-import java.security.PrivateKey;
import java.time.Instant;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.UUID;
+import java.util.function.Function;
import static org.eclipse.edc.identithub.verifiablepresentation.generators.PresentationGeneratorConstants.CONTROLLER_ADDITIONAL_DATA;
import static org.eclipse.edc.identithub.verifiablepresentation.generators.PresentationGeneratorConstants.VERIFIABLE_CREDENTIAL_PROPERTY;
@@ -60,15 +59,15 @@ public class LdpPresentationGenerator implements PresentationGenerator<JsonObjec
public static final String TYPE_ADDITIONAL_DATA = "types";
public static final String HOLDER_PROPERTY = "holder";
public static final URI ASSERTION_METHOD = URI.create("https://w3id.org/security#assertionMethod");
- private final PrivateKeyResolver privateKeyResolver;
+ private final Function<String, JWSSigner> jwsSignerResolver;
private final SignatureSuiteRegistry signatureSuiteRegistry;
private final String defaultSignatureSuite;
private final LdpIssuer ldpIssuer;
private final ObjectMapper mapper;
- public LdpPresentationGenerator(PrivateKeyResolver privateKeyResolver,
+ public LdpPresentationGenerator(Function<String, JWSSigner> jwsSignerResolver,
SignatureSuiteRegistry signatureSuiteRegistry, String defaultSignatureSuite, LdpIssuer ldpIssuer, ObjectMapper mapper) {
- this.privateKeyResolver = privateKeyResolver;
+ this.jwsSignerResolver = jwsSignerResolver;
this.signatureSuiteRegistry = signatureSuiteRegistry;
this.defaultSignatureSuite = defaultSignatureSuite;
this.ldpIssuer = ldpIssuer;
@@ -121,9 +120,6 @@ public class LdpPresentationGenerator implements PresentationGenerator<JsonObjec
throw new IllegalArgumentException("One or more VerifiableCredentials cannot be represented in the desired format " + CredentialFormat.JSON_LD);
}
- // check if private key can be resolved
- var pk = privateKeyResolver.resolvePrivateKey(privateKeyAlias)
- .orElseThrow(f -> new IllegalArgumentException(f.getFailureDetail()));
var types = (List) additionalData.get(TYPE_ADDITIONAL_DATA);
var presentationObject = Json.createObjectBuilder()
@@ -134,7 +130,9 @@ public class LdpPresentationGenerator implements PresentationGenerator<JsonObjec
.add(VERIFIABLE_CREDENTIAL_PROPERTY, toJsonArray(credentials))
.build();
- return signPresentation(presentationObject, suite, suiteIdentifier, pk, publicKeyId, additionalData.get(CONTROLLER_ADDITIONAL_DATA).toString());
+ JWSSigner jwsSigner = jwsSignerResolver.apply(privateKeyAlias);
+ return signPresentation(presentationObject, suite, suiteIdentifier, jwsSigner, publicKeyId,
+ additionalData.get(CONTROLLER_ADDITIONAL_DATA).toString());
}
@NotNull
@@ -153,26 +151,57 @@ public class LdpPresentationGenerator implements PresentationGenerator<JsonObjec
return array.build();
}
- private JsonObject signPresentation(JsonObject presentationObject, SignatureSuite suite, String suiteIdentifier, PrivateKey pk, String publicKeyId, String controller) {
- var keyIdUri = URI.create(publicKeyId);
+ private JsonObject signPresentation(JsonObject presentationObject, SignatureSuite suite, String suiteIdentifier,
+ JWSSigner jwsSigner, String publicKeyId, String controller) {
var controllerUri = URI.create(controller);
var verificationMethodType = URI.create(suiteIdentifier);
- var jwk = CryptoConverter.createJwk(new KeyPair(null, pk));
-
- var keypair = new JsonWebKeyPair(keyIdUri, verificationMethodType, controllerUri, jwk);
-
var proofDraft = Jws2020ProofDraft.Builder.newInstance()
+ .jwsSigner(jwsSigner)
.proofPurpose(ASSERTION_METHOD)
.verificationMethod(new JsonWebKeyPair(URI.create(controller + "#" + publicKeyId), verificationMethodType, controllerUri, null))
.created(Instant.now())
.mapper(mapper)
.build();
- return ldpIssuer.signDocument(suite, presentationObject, keypair, proofDraft)
+ return ldpIssuer.signDocument(suite, presentationObject, keyPairMock(), proofDraft)
.orElseThrow(f -> new EdcException(f.getFailureDetail()));
}
+ KeyPair keyPairMock() {
+ return new KeyPair() {
+ @Override
+ public byte[] privateKey() {
+ return new byte[0];
+ }
+
+ @Override
+ public String algorithm() {
+ return null;
+ }
+
+ @Override
+ public byte[] publicKey() {
+ return new byte[0];
+ }
+
+ @Override
+ public URI id() {
+ return null;
+ }
+
+ @Override
+ public URI type() {
+ return null;
+ }
+
+ @Override
+ public URI controller() {
+ return null;
+ }
+ };
+ }
+
private JsonArrayBuilder stringArray(Collection<?> values) {
var ja = Json.createArrayBuilder();
values.forEach(s -> ja.add(s.toString()));
diff --git spi/verifiable-credential-spi/build.gradle.kts spi/verifiable-credential-spi/build.gradle.kts
index 75fb756..456534f 100644
--- spi/verifiable-credential-spi/build.gradle.kts
+++ spi/verifiable-credential-spi/build.gradle.kts
@@ -24,9 +24,9 @@ dependencies {
api(project(":spi:participant-context-spi"))
api(libs.edc.spi.dcp)
+ implementation(libs.nimbus.jwt)
testImplementation(libs.edc.lib.json)
- testFixturesImplementation(libs.nimbus.jwt)
testFixturesImplementation(libs.edc.spi.identity.did)
testFixturesImplementation(libs.edc.common.crypto)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment