diff --git a/extensions/common/crypto/jws2020/src/testFixtures/java/org/eclipse/edc/security/signature/jws2020/TestFunctions.java b/extensions/common/crypto/jws2020/src/testFixtures/java/org/eclipse/edc/security/signature/jws2020/TestFunctions.java index 84488d7ee47..4884680af58 100644 --- a/extensions/common/crypto/jws2020/src/testFixtures/java/org/eclipse/edc/security/signature/jws2020/TestFunctions.java +++ b/extensions/common/crypto/jws2020/src/testFixtures/java/org/eclipse/edc/security/signature/jws2020/TestFunctions.java @@ -38,7 +38,7 @@ public static KeyPair createKeyPair(JWK jwk) { return new JwkMethod(id, type, null, jwk); } - static JsonObject readResourceAsJson(String name) { + public static JsonObject readResourceAsJson(String name) { try { return MAPPER.readValue(getResourceFileContentAsString(name), JsonObject.class); } catch (IOException e) { diff --git a/extensions/common/crypto/ldp-verifiable-credentials/src/main/java/org/eclipse/edc/verifiablecredentials/linkeddata/LdpIssuer.java b/extensions/common/crypto/ldp-verifiable-credentials/src/main/java/org/eclipse/edc/verifiablecredentials/linkeddata/LdpIssuer.java new file mode 100644 index 00000000000..f4a2f7532fb --- /dev/null +++ b/extensions/common/crypto/ldp-verifiable-credentials/src/main/java/org/eclipse/edc/verifiablecredentials/linkeddata/LdpIssuer.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +package org.eclipse.edc.verifiablecredentials.linkeddata; + +import com.apicatalog.jsonld.JsonLdReader; +import com.apicatalog.jsonld.loader.DocumentLoader; +import com.apicatalog.jsonld.loader.SchemeRouter; +import com.apicatalog.ld.DocumentError; +import com.apicatalog.ld.signature.LinkedDataSignature; +import com.apicatalog.ld.signature.SigningError; +import com.apicatalog.ld.signature.key.KeyPair; +import com.apicatalog.ld.signature.proof.EmbeddedProof; +import com.apicatalog.ld.signature.proof.ProofOptions; +import com.apicatalog.vc.VcTag; +import com.apicatalog.vc.loader.StaticContextLoader; +import jakarta.json.Json; +import jakarta.json.JsonObject; +import jakarta.json.JsonValue; +import org.eclipse.edc.jsonld.spi.JsonLd; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.result.Result; + +import java.net.URI; +import java.util.Objects; + +/** + * The LdpIssuer class is responsible for signing JSON-LD documents (e.g. VerifiableCredentials, VerifiablePresentations) using Linked Data Proofs (LDP). + * It provides methods for signing a document with a given key pair and proof options. + */ +public class LdpIssuer { + // mandatory properties + private JsonLd jsonLdService; + private DocumentLoader loader; + private boolean bundledContexts; + private URI base; + private Monitor monitor; + + private LdpIssuer() { + } + + /** + * Sign a document using a given key pair and proof options. Effectively, this method adds a {@code proof}-object to the JSON document. + * The document is expanded internally, using the {@link JsonLd} interface. + * + * @param document The document to sign. + * @param keyPair The key pair used for signing. + * @param proofOptions The proof options. + * @return A result containing the signed document as a JsonObject, a failure otherwise. + * @throws NullPointerException If any of the parameters is null. + */ + public Result signDocument(JsonObject document, KeyPair keyPair, ProofOptions proofOptions) { + Objects.requireNonNull(document, "Document must not be null"); + Objects.requireNonNull(document, "KeyPair must not be null"); + Objects.requireNonNull(document, "ProofOptions must not be null"); + if (loader == null) { + // default loader + loader = SchemeRouter.defaultInstance(); + } + + if (bundledContexts) { + loader = new StaticContextLoader(loader); + } + + return jsonLdService.expand(document) + .compose(expanded -> signExpanded(expanded, keyPair, proofOptions)); + + } + + private Result signExpanded(JsonObject expanded, KeyPair keyPair, ProofOptions options) { + + var optionalObject = JsonLdReader.findFirstObject(expanded); + if (optionalObject.isEmpty()) { + return Result.failure("Error reading document: %s".formatted(DocumentError.ErrorType.Invalid)); + } + var object = optionalObject.get(); + + if (options.getSuite() == null) { + return Result.failure("Unsupported Crypto Suite: %s".formatted(SigningError.Code.UnsupportedCryptoSuite)); + } + + var data = EmbeddedProof.removeProof(object); + + var ldSignature = new LinkedDataSignature(options.getSuite().getCryptoSuite()); + + JsonObject proof; + try { + proof = options.getSuite().getSchema().write(options.toUnsignedProof()); + } catch (DocumentError e) { + monitor.warning("Error writing proof", e); + return Result.failure("Error writing proof: %s".formatted(e.getMessage())); + } + + var proofValueProperty = options.getSuite().getSchema().tagged(VcTag.ProofValue.name()); + + byte[] signature; + try { + signature = ldSignature.sign(data, keyPair, proof); + } catch (SigningError e) { + monitor.warning("Error signing data", e); + return Result.failure("Error signing data: %s".formatted(e.getMessage())); + } + + JsonValue proofValue; + try { + proofValue = proofValueProperty.write(signature); + } catch (DocumentError e) { + monitor.warning("Error writing signature value to document", e); + return Result.failure("Error writing signature to document: %s".formatted(e.getCode())); + } + + proof = Json.createObjectBuilder(proof) + .add(proofValueProperty.term().uri(), Json.createArrayBuilder().add(proofValue)) + .build(); + + return Result.success(EmbeddedProof.addProof(object, proof)); + } + + + public static final class Builder { + private final LdpIssuer ldpIssuer; + + private Builder() { + ldpIssuer = new LdpIssuer(); + } + + public static Builder newInstance() { + return new Builder(); + } + + public Builder jsonLd(JsonLd jsonLd) { + this.ldpIssuer.jsonLdService = jsonLd; + return this; + } + + public Builder loader(DocumentLoader loader) { + this.ldpIssuer.loader = loader; + return this; + } + + public Builder bundledContexts(boolean bundledContexts) { + this.ldpIssuer.bundledContexts = bundledContexts; + return this; + } + + public Builder base(URI base) { + this.ldpIssuer.base = base; + return this; + } + + public Builder monitor(Monitor monitor) { + this.ldpIssuer.monitor = monitor; + return this; + } + + public LdpIssuer build() { + Objects.requireNonNull(ldpIssuer.jsonLdService, "Must have a JsonLd instance"); + Objects.requireNonNull(ldpIssuer.monitor, "Monitor cannot be null"); + return ldpIssuer; + } + } +} diff --git a/extensions/common/crypto/ldp-verifiable-credentials/src/test/java/org/eclipse/edc/verifiablecredentials/linkeddata/LdpIssuerTest.java b/extensions/common/crypto/ldp-verifiable-credentials/src/test/java/org/eclipse/edc/verifiablecredentials/linkeddata/LdpIssuerTest.java new file mode 100644 index 00000000000..b4bbea30112 --- /dev/null +++ b/extensions/common/crypto/ldp-verifiable-credentials/src/test/java/org/eclipse/edc/verifiablecredentials/linkeddata/LdpIssuerTest.java @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +package org.eclipse.edc.verifiablecredentials.linkeddata; + +import com.apicatalog.ld.DocumentError; +import com.apicatalog.ld.signature.SigningError; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.nimbusds.jose.JOSEException; +import com.nimbusds.jose.jwk.Curve; +import com.nimbusds.jose.jwk.ECKey; +import com.nimbusds.jose.jwk.JWK; +import com.nimbusds.jose.jwk.KeyUse; +import com.nimbusds.jose.jwk.RSAKey; +import com.nimbusds.jose.jwk.gen.ECKeyGenerator; +import com.nimbusds.jose.jwk.gen.OctetKeyPairGenerator; +import jakarta.json.JsonArray; +import jakarta.json.JsonValue; +import org.eclipse.edc.jsonld.TitaniumJsonLd; +import org.eclipse.edc.jsonld.spi.JsonLdKeywords; +import org.eclipse.edc.security.signature.jws2020.JwkMethod; +import org.eclipse.edc.security.signature.jws2020.JwsSignature2020Suite; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.net.URI; +import java.net.URISyntaxException; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.text.ParseException; +import java.time.Instant; +import java.util.Date; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.edc.jsonld.util.JacksonJsonLd.createObjectMapper; +import static org.eclipse.edc.security.signature.jws2020.TestFunctions.createKeyPair; +import static org.eclipse.edc.security.signature.jws2020.TestFunctions.readResourceAsJson; +import static org.mockito.Mockito.mock; + +class LdpIssuerTest { + private final ObjectMapper mapper = createObjectMapper(); + + @Nested + class JsonWegSignature2020 { + private final JwsSignature2020Suite jws2020suite = new JwsSignature2020Suite(mapper); + private LdpIssuer issuer; + + @BeforeEach + void setup() throws URISyntaxException { + var jsonLd = new TitaniumJsonLd(mock()); + var ccl = Thread.currentThread().getContextClassLoader(); + jsonLd.registerCachedDocument("https://www.w3.org/ns/odrl.jsonld", ccl.getResource("odrl.jsonld").toURI()); + jsonLd.registerCachedDocument("https://www.w3.org/ns/did/v1", ccl.getResource("jws2020.json").toURI()); + jsonLd.registerCachedDocument("https://w3id.org/security/suites/jws-2020/v1", ccl.getResource("jws2020.json").toURI()); + jsonLd.registerCachedDocument("https://www.w3.org/2018/credentials/v1", ccl.getResource("credentials.v1.json").toURI()); + jsonLd.registerCachedDocument("https://www.w3.org/2018/credentials/examples/v1", ccl.getResource("examples.v1.json").toURI()); + issuer = LdpIssuer.Builder.newInstance() + .jsonLd(jsonLd) + .monitor(mock()) + .build(); + } + + @DisplayName("t0001: a simple credential to sign (EC Key)") + @Test + void signSimpleCredential_ecKey() throws JOSEException { + var vc = readResourceAsJson("jws2020/issuing/0001_vc.json"); + var keypair = createKeyPair(new ECKeyGenerator(Curve.P_384).keyID("test-kid").generate()); + + var verificationMethodUrl = "https://org.eclipse.edc/verification-method"; + + var proofOptions = jws2020suite.createOptions() + .created(Instant.parse("2022-12-31T23:00:00Z")) + .verificationMethod(new JwkMethod(URI.create(verificationMethodUrl), null, null, null)) + .purpose(URI.create("https://w3id.org/security#assertionMethod")); + + + var result = issuer.signDocument(vc, keypair, proofOptions); + assertThat(result.succeeded()).withFailMessage(result::getFailureDetail).isTrue(); + var verificationMethod = result.getContent().getJsonArray("https://w3id.org/security#proof").get(0).asJsonObject().get("https://w3id.org/security#verificationMethod"); + + assertThat(verificationMethod.getValueType()).describedAs("Expected a String!").isEqualTo(JsonValue.ValueType.ARRAY); + assertThat(verificationMethod.asJsonArray().get(0).asJsonObject().toString()).contains(verificationMethodUrl); + } + + @DisplayName("t0001: a simple credential to sign (RSA Key)") + @ParameterizedTest(name = "keySize = {0} bits") + @ValueSource(ints = { 2048, 3072, 4096 }) + void signSimpleCredential_rsaKey(int keysize) throws SigningError, DocumentError, NoSuchAlgorithmException { + var vc = readResourceAsJson("jws2020/issuing/0001_vc.json"); + + var gen = KeyPairGenerator.getInstance("RSA"); + gen.initialize(keysize); + var keyPair = gen.generateKeyPair(); + + var jwk = new RSAKey.Builder((RSAPublicKey) keyPair.getPublic()) + .privateKey((RSAPrivateKey) keyPair.getPrivate()) + .keyUse(KeyUse.SIGNATURE) + .keyID(UUID.randomUUID().toString()) + .issueTime(new Date()) + .build(); + var keypair = createKeyPair(jwk); + + var verificationMethodUrl = "https://org.eclipse.edc/verification-method"; + + var proofOptions = jws2020suite.createOptions() + .created(Instant.parse("2022-12-31T23:00:00Z")) + .verificationMethod(new JwkMethod(URI.create(verificationMethodUrl), null, null, null)) + .purpose(URI.create("https://w3id.org/security#assertionMethod")); + + var result = issuer.signDocument(vc, keypair, proofOptions); + assertThat(result.succeeded()).withFailMessage(result::getFailureDetail).isTrue(); + var verificationMethod = result.getContent().getJsonArray("https://w3id.org/security#proof").get(0).asJsonObject().get("https://w3id.org/security#verificationMethod"); + + assertThat(verificationMethod.getValueType()).describedAs("Expected a String!").isEqualTo(JsonValue.ValueType.ARRAY); + assertThat(verificationMethod.asJsonArray().get(0).asJsonObject().toString()).contains(verificationMethodUrl); + } + + @DisplayName("t0001: a simple credential to sign (OctetKeyPair)") + @Test + void signSimpleCredential_octetKeyPair() throws SigningError, DocumentError, JOSEException { + var vc = readResourceAsJson("jws2020/issuing/0001_vc.json"); + + var jwk = new OctetKeyPairGenerator(Curve.Ed25519).generate(); + var keypair = createKeyPair(jwk); + + var verificationMethodUrl = "https://org.eclipse.edc/verification-method"; + + var proofOptions = jws2020suite.createOptions() + .created(Instant.parse("2022-12-31T23:00:00Z")) + .verificationMethod(new JwkMethod(URI.create(verificationMethodUrl), null, null, null)) + .purpose(URI.create("https://w3id.org/security#assertionMethod")); + + + var result = issuer.signDocument(vc, keypair, proofOptions); + assertThat(result.succeeded()).withFailMessage(result::getFailureDetail).isTrue(); + var verificationMethod = result.getContent().getJsonArray("https://w3id.org/security#proof").get(0).asJsonObject().get("https://w3id.org/security#verificationMethod"); + + assertThat(verificationMethod.getValueType()).describedAs("Expected a String!").isEqualTo(JsonValue.ValueType.ARRAY); + assertThat(verificationMethod.asJsonArray().get(0).asJsonObject().toString()).contains(verificationMethodUrl); + } + + @DisplayName("t0003: signed embedded verificationMethod") + @Test + void signEmbeddedVerificationMethod() throws JOSEException { + var vc = readResourceAsJson("jws2020/issuing/0001_vc.json"); + var keypair = createKeyPair(new ECKeyGenerator(Curve.P_384).keyID("test-kid").generate()); + + var proofOptions = jws2020suite.createOptions() + .created(Instant.parse("2022-12-31T23:00:00Z")) + .verificationMethod(keypair) + .purpose(URI.create("https://w3id.org/security#assertionMethod")); + + + var result = issuer.signDocument(vc, keypair, proofOptions); + assertThat(result.succeeded()).withFailMessage(result::getFailureDetail).isTrue(); + var verificationMethod = result.getContent().getJsonArray("https://w3id.org/security#proof").get(0).asJsonObject().get("https://w3id.org/security#verificationMethod"); + + assertThat(verificationMethod).withFailMessage("Expected an JsonArray!").isInstanceOf(JsonArray.class); + assertThat(verificationMethod.asJsonArray().get(0).asJsonObject().get("https://w3id.org/security#publicKeyJwk")) + .isInstanceOf(JsonArray.class) + .satisfies(jv -> { + var jwk = ((JsonArray) jv).get(0).asJsonObject().get(JsonLdKeywords.VALUE); + assertThat(jwk.asJsonObject().get("x")).isNotNull(); + assertThat(jwk.asJsonObject().get("crv")).isNotNull(); + assertThat(jwk.asJsonObject().get("kty")).isNotNull(); + }); + } + + @DisplayName("t0004: a credential with DID key as verification method") + @Test + void signVerificationDidKey() throws SigningError, DocumentError, ParseException { + var vc = readResourceAsJson("jws2020/issuing/0001_vc.json"); + var eckey = (ECKey) JWK.parse(""" + { + "kty": "EC", + "d": "UEUJVbKZC3vR-y65gXx8NZVnE0QD5xe6qOk4eiObj-qVOg5zqt9zc0d6fdu4mUuu", + "use": "sig", + "crv": "P-384", + "x": "l6IS348kIFEANYl3CWueMYVXcZmK0eMI0vejkF1GHbl77dOZuZwi9L2IQmuA27ux", + "y": "m-8s5FM8Tn00OKVFxE-wfCs3J2keE2EBAYYZgAmfI1LCRD9iU2LBced-EBK18Da9", + "alg": "ES384" + } + """); + var keypair = createKeyPair(eckey); + + // check https://w3c-ccg.github.io/did-method-key/#create for details + var didKey = "did:key:zC2zU1wUHhYYX4CDwNwky9f5jtSvp5aQy5aNRQMHEdpK5xkJMy6TcMbWBP3scHbR6hhidR3RRjfAA7cuLxjydXgEiZUzRzguozYFeR3G6SzjAwswJ6hXKBWhFEHm2L6Rd6GRAw8r3kyPovxvcabdMF2gBy5TAioY1mVYFeT6"; + + var proofOptions = jws2020suite.createOptions() + .created(Instant.parse("2022-12-31T23:00:00Z")) + .verificationMethod(new JwkMethod(URI.create(didKey), null, null, null)) + .purpose(URI.create("https://w3id.org/security#assertionMethod")); + + + var result = issuer.signDocument(vc, keypair, proofOptions); + assertThat(result.succeeded()).withFailMessage(result::getFailureDetail).isTrue(); + var verificationMethod = result.getContent().getJsonArray("https://w3id.org/security#proof").get(0).asJsonObject().get("https://w3id.org/security#verificationMethod"); + + assertThat(verificationMethod.getValueType()).describedAs("Expected a String!").isEqualTo(JsonValue.ValueType.ARRAY); + assertThat(verificationMethod.asJsonArray().get(0).asJsonObject().toString()).contains(didKey); + + + } + + @DisplayName("t0005: compacted signed presentation") + @Test + void signCompactedPresentation() throws JOSEException { + var vp = readResourceAsJson("jws2020/issuing/0005_vp_compacted_signed.json"); + + var keypair = createKeyPair(new ECKeyGenerator(Curve.P_384).keyID("test-kid").generate()); + + var verificationMethodUrl = "https://org.eclipse.edc/verification-method"; + + var proofOptions = jws2020suite.createOptions() + .created(Instant.parse("2022-12-31T23:00:00Z")) + .verificationMethod(new JwkMethod(URI.create(verificationMethodUrl), null, null, null)) + .purpose(URI.create("https://w3id.org/security#assertionMethod")); + + + var result = issuer.signDocument(vp, keypair, proofOptions); + assertThat(result.succeeded()).withFailMessage(result::getFailureDetail).isTrue(); + var verificationMethod = result.getContent().getJsonArray("https://w3id.org/security#proof").get(0).asJsonObject().get("https://w3id.org/security#verificationMethod"); + + assertThat(verificationMethod.getValueType()).describedAs("Expected a String!").isEqualTo(JsonValue.ValueType.ARRAY); + assertThat(verificationMethod.asJsonArray().get(0).asJsonObject().toString()).contains(verificationMethodUrl); + } + } +} \ No newline at end of file diff --git a/extensions/common/crypto/ldp-verifiable-credentials/src/test/resources/jws2020/issuing/0001_vc.json b/extensions/common/crypto/ldp-verifiable-credentials/src/test/resources/jws2020/issuing/0001_vc.json new file mode 100644 index 00000000000..f23ce7a2556 --- /dev/null +++ b/extensions/common/crypto/ldp-verifiable-credentials/src/test/resources/jws2020/issuing/0001_vc.json @@ -0,0 +1,20 @@ +{ + "issuanceDate": "2023-06-12T13:13:30Z", + "credentialSubject": { + "number": "member0123456789", + "id": "did:web:localhost:member0123456789", + "type": "https://org.eclipse.edc/linkedCredentialData#MembershipCredential" + }, + "id": "https://org.eclipse.edc/testcases/t0001", + "type": [ + "VerifiableCredential", + "MembershipCredential" + ], + "issuer": "did:web:localhost:member0123456789", + "expirationDate": "2024-12-31T23:00:00Z", + "@context": [ + "https://www.w3.org/ns/did/v1", + "https://www.w3.org/2018/credentials/v1", + "https://w3id.org/security/suites/jws-2020/v1" + ] +} \ No newline at end of file diff --git a/extensions/common/crypto/ldp-verifiable-credentials/src/test/resources/jws2020/issuing/0003_vc_embedded.json b/extensions/common/crypto/ldp-verifiable-credentials/src/test/resources/jws2020/issuing/0003_vc_embedded.json new file mode 100644 index 00000000000..6c4bab7066d --- /dev/null +++ b/extensions/common/crypto/ldp-verifiable-credentials/src/test/resources/jws2020/issuing/0003_vc_embedded.json @@ -0,0 +1,21 @@ +{ + "issuanceDate": "2023-06-12T13:13:30Z", + "credentialSubject": { + "number": "member0123456789", + "id": "did:web:localhost:member0123456789", + "type": "MembershipCredential" + }, + "id": "https://org.eclipse.edc/testcases/t0001", + "type": [ + "VerifiableCredential", + "MembershipCredential" + ], + "issuer": "did:web:localhost:member0123456789", + "expirationDate": "2024-12-31T23:00:00Z", + "@context": [ + "https://org.eclipse.edc/linkedCredentialData", + "https://www.w3.org/ns/did/v1", + "https://www.w3.org/2018/credentials/v1", + "https://w3id.org/security/suites/jws-2020/v1" + ] +} \ No newline at end of file diff --git a/extensions/common/crypto/ldp-verifiable-credentials/src/test/resources/jws2020/issuing/0004_vc_did_key.json b/extensions/common/crypto/ldp-verifiable-credentials/src/test/resources/jws2020/issuing/0004_vc_did_key.json new file mode 100644 index 00000000000..5920bbb6c67 --- /dev/null +++ b/extensions/common/crypto/ldp-verifiable-credentials/src/test/resources/jws2020/issuing/0004_vc_did_key.json @@ -0,0 +1,21 @@ +{ + "issuanceDate": "2023-06-12T13:13:30Z", + "credentialSubject": { + "http://schema.org/identifier": "member0123456789", + "id": "did:web:localhost:member0123456789", + "type": "https://org.eclipse.edc/linkedCredentialData#MembershipCredential" + }, + "id": "https://org.eclipse.edc/testcases/t0001", + "type": [ + "VerifiableCredential", + "MembershipCredential" + ], + "issuer": "did:web:localhost:member0123456789", + "expirationDate": "2024-12-31T23:00:00Z", + "@context": [ + "https://org.eclipse.edc/linkedCredentialData", + "https://www.w3.org/ns/did/v1", + "https://www.w3.org/2018/credentials/v1", + "https://w3id.org/security/suites/jws-2020/v1" + ] +} diff --git a/extensions/common/crypto/ldp-verifiable-credentials/src/test/resources/jws2020/issuing/0005_vp_compacted_signed.json b/extensions/common/crypto/ldp-verifiable-credentials/src/test/resources/jws2020/issuing/0005_vp_compacted_signed.json new file mode 100644 index 00000000000..3aa9c206676 --- /dev/null +++ b/extensions/common/crypto/ldp-verifiable-credentials/src/test/resources/jws2020/issuing/0005_vp_compacted_signed.json @@ -0,0 +1,37 @@ +{ + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://www.w3.org/2018/credentials/examples/v1" + ], + "id": "urn:uuid:3978344f-8596-4c3a-a978-8fcaba3903c5", + "type": "VerifiablePresentation", + "verifiableCredential": [ + { + "issuanceDate": "2023-06-12T13:13:30Z", + "credentialSubject": { + "number": "member0123456789", + "id": "did:web:localhost:member0123456789", + "type": "MembershipCredential" + }, + "id": "https://org.eclipse.edc/testcases/t0001", + "type": [ + "VerifiableCredential", + "MembershipCredential" + ], + "issuer": "did:web:localhost:member0123456789", + "expirationDate": "2024-12-31T23:00:00Z", + "sec:proof": { + "type": "JsonWebSignature2020", + "created": "2022-12-31T23:00:00Z", + "proofPurpose": "assertionMethod", + "verificationMethod": "https://org.eclipse.edc/verification-method", + "jws": "eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFUzM4NCJ9..dbi6LFkdeBeCz3sHaxRRFVJC2_rF8Z_oYqaoNOpYtzQh61WP78pK7nKT53WsE-7uiBUMamLA8vEGJpFQ3h4MXDi2OKh1YDpphS_pwyDkqYbsguMs2KYqPxe8t1OC2G1o" + }, + "@context": [ + "https://www.w3.org/ns/did/v1", + "https://www.w3.org/2018/credentials/v1", + "https://w3id.org/security/suites/jws-2020/v1" + ] + } + ] +} \ No newline at end of file