From 126d510a2602c706e94f82374f364e95c5454fe0 Mon Sep 17 00:00:00 2001 From: Mustafa Alsalfiti Date: Tue, 27 Feb 2024 13:38:17 +0100 Subject: [PATCH 01/15] fix: add serialized jwt vc factory impl and signed jwt factory --- .../org/eclipse/tractusx/ssi/examples/VP.java | 11 +- .../ssi/lib/jwt/SignedJwtFactory.java | 104 ++++++++++----- .../ssi/lib/serialization/jwt/JwtConfig.java | 30 +++++ .../jwt/SerializedJwtPresentationFactory.java | 17 ++- .../SerializedJwtPresentationFactoryImpl.java | 51 +++++--- .../jwt/SerializedJwtVCFactory.java | 38 ++++++ .../jwt/SerializedJwtVCFactoryImpl.java | 49 ++++++++ ...ializedJwtPresentationFactoryImplTest.java | 118 +++++++++++------- 8 files changed, 320 insertions(+), 98 deletions(-) create mode 100644 src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/JwtConfig.java create mode 100644 src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtVCFactory.java create mode 100644 src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtVCFactoryImpl.java diff --git a/src/main/java/org/eclipse/tractusx/ssi/examples/VP.java b/src/main/java/org/eclipse/tractusx/ssi/examples/VP.java index 4a18b66b..0ee66ea9 100644 --- a/src/main/java/org/eclipse/tractusx/ssi/examples/VP.java +++ b/src/main/java/org/eclipse/tractusx/ssi/examples/VP.java @@ -1,6 +1,5 @@ -/* - * ****************************************************************************** - * Copyright (c) 2021,2023 Contributors to the Eclipse Foundation +/******************************************************************************** + * Copyright (c) 2021,2024 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -16,8 +15,7 @@ * under the License. * * SPDX-License-Identifier: Apache-2.0 - * ******************************************************************************* - */ + ********************************************************************************/ package org.eclipse.tractusx.ssi.examples; @@ -90,6 +88,7 @@ public static SignedJWT createVPAsJWT( new SerializedJwtPresentationFactoryImpl( new SignedJwtFactory(new OctetKeyPairFactory()), new JsonLdSerializerImpl(), issuer); - return presentationFactory.createPresentation(issuer, credentials, audience, privateKey); + return presentationFactory.createPresentation( + issuer, credentials, audience, privateKey, "keyId"); } } diff --git a/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java b/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java index e2ad9e64..59ea8dab 100644 --- a/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java +++ b/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java @@ -1,5 +1,4 @@ -/* - * ****************************************************************************** +/******************************************************************************** * Copyright (c) 2021,2024 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional @@ -16,11 +15,11 @@ * under the License. * * SPDX-License-Identifier: Apache-2.0 - * ******************************************************************************* - */ + ********************************************************************************/ package org.eclipse.tractusx.ssi.lib.jwt; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.nimbusds.jose.JOSEObjectType; import com.nimbusds.jose.JWSAlgorithm; @@ -30,33 +29,47 @@ import com.nimbusds.jose.jwk.OctetKeyPair; import com.nimbusds.jwt.JWTClaimsSet; import com.nimbusds.jwt.SignedJWT; -import java.net.URI; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.stream.Collectors; import lombok.SneakyThrows; import org.eclipse.tractusx.ssi.lib.crypt.IPrivateKey; import org.eclipse.tractusx.ssi.lib.crypt.octet.OctetKeyPairFactory; import org.eclipse.tractusx.ssi.lib.model.did.Did; +import org.eclipse.tractusx.ssi.lib.model.verifiable.credential.VerifiableCredential; +import org.eclipse.tractusx.ssi.lib.serialization.jwt.JwtConfig; import org.eclipse.tractusx.ssi.lib.serialization.jwt.SerializedVerifiablePresentation; /** - * Convenience/helper class to generate and verify Signed JSON Web Tokens (JWTs) for communicating - * between connector instances. + * Convenience/helper class to generate * Convenience/helper class to generate and verify Signed + * JSON Web Tokens (JWTs) for communicating between connector instances. */ public class SignedJwtFactory { private final OctetKeyPairFactory octetKeyPairFactory; + public SignedJwtFactory(OctetKeyPairFactory octetKeyPairFactory) { + this.octetKeyPairFactory = Objects.requireNonNull(octetKeyPairFactory); + } + /** - * Instantiates a new Signed jwt factory. + * Creates a signed JWT {@link SignedJWT} that contains a set of claims and an issuer. Although + * all private key types are possible, in the context of Distributed Identity using an Elliptic + * Curve key ({@code P-256}) is advisable. * - * @param octetKeyPairFactory the octet key pair factory + * @param audience the value of the token audience claim, e.g. the IDS Webhook address. + * @param keyId the id of the key, the kid of the jws-header will be constructed via + * +"#"+ + * @return a {@code SignedJWT} that is signed with the private key and contains all claims listed. */ - public SignedJwtFactory(OctetKeyPairFactory octetKeyPairFactory) { - this.octetKeyPairFactory = Objects.requireNonNull(octetKeyPairFactory); + @SneakyThrows + public SignedJWT create( + Did didIssuer, + String audience, + SerializedVerifiablePresentation serializedPresentation, + IPrivateKey privateKey, + String keyId) { + JwtConfig jwtConfig = JwtConfig.builder().expirationTime(60).build(); + return create(didIssuer, audience, serializedPresentation, privateKey, keyId, jwtConfig); } /** @@ -64,26 +77,32 @@ public SignedJwtFactory(OctetKeyPairFactory octetKeyPairFactory) { * all private key types are possible, in the context of Distributed Identity using an Elliptic * Curve key ({@code P-256}) is advisable. * - * @param didIssuer the did issuer * @param audience the value of the token audience claim, e.g. the IDS Webhook address. - * @param serializedPresentation the serialized presentation - * @param privateKey the private key + * @param keyId the id of the key, the kid of the jws-header will be constructed via + * +"#"+ + * @param config the custom configuration for the JWT to create, e.g. custom expiration time (exp) * @return a {@code SignedJWT} that is signed with the private key and contains all claims listed. */ @SneakyThrows public SignedJWT create( - URI id, Did didIssuer, String audience, SerializedVerifiablePresentation serializedPresentation, - IPrivateKey privateKey) { + IPrivateKey privateKey, + String keyId, + JwtConfig config) { final String issuer = didIssuer.toString(); final String subject = didIssuer.toString(); + TypeReference> typeRef = + new TypeReference>() {}; + // make on object out of it so that it can get serialized again Map vp = - new ObjectMapper().readValue(serializedPresentation.getJson(), HashMap.class); + new ObjectMapper().readValue(serializedPresentation.getJson(), typeRef); + + Date iat = new Date(); var claimsSet = new JWTClaimsSet.Builder() @@ -91,16 +110,43 @@ public SignedJWT create( .subject(subject) .audience(audience) .claim("vp", vp) - .expirationTime(new Date(new Date().getTime() + 60 * 1000)) - .jwtID(id.toString()) + .issueTime(iat) + .expirationTime(new Date(iat.getTime() + config.getExpirationTime() * 1000)) + .jwtID(UUID.randomUUID().toString()) + .build(); + + final OctetKeyPair octetKeyPair = octetKeyPairFactory.fromPrivateKey(privateKey); + return createSignedES256Jwt(octetKeyPair, claimsSet, issuer, keyId); + } + + @SneakyThrows + public SignedJWT create( + Did didIssuer, + Did holderIssuer, + Date expDate, + LinkedHashMap vc, + IPrivateKey privateKey, + String keyId) { + final String issuer = didIssuer.toString(); + final String subject = holderIssuer.toString(); + + vc.remove(VerifiableCredential.PROOF); + + var claimsSet = + new JWTClaimsSet.Builder() + .issuer(issuer) + .subject(subject) + .claim("vc", vc) + .expirationTime(expDate) + .jwtID(UUID.randomUUID().toString()) .build(); final OctetKeyPair octetKeyPair = octetKeyPairFactory.fromPrivateKey(privateKey); - return createSignedES256Jwt(octetKeyPair, claimsSet, issuer); + return createSignedES256Jwt(octetKeyPair, claimsSet, issuer, keyId); } - private static SignedJWT createSignedES256Jwt( - OctetKeyPair privateKey, JWTClaimsSet claimsSet, String issuer) { + public SignedJWT createSignedES256Jwt( + OctetKeyPair privateKey, JWTClaimsSet claimsSet, String issuer, String keyId) { JWSSigner signer; try { @@ -116,11 +162,7 @@ private static SignedJWT createSignedES256Jwt( var algorithm = JWSAlgorithm.EdDSA; var type = JOSEObjectType.JWT; - - JWSHeader.Builder jwsHeaderBuilder = - new JWSHeader.Builder(algorithm).type(type).keyID(issuer).base64URLEncodePayload(true); - - var header = jwsHeaderBuilder.build(); + var header = new JWSHeader.Builder(algorithm).type(type).keyID(issuer + "#" + keyId).build(); var vc = new SignedJWT(header, claimsSet); vc.sign(signer); diff --git a/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/JwtConfig.java b/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/JwtConfig.java new file mode 100644 index 00000000..7d45c369 --- /dev/null +++ b/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/JwtConfig.java @@ -0,0 +1,30 @@ +/******************************************************************************** + * Copyright (c) 2021,2023 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * 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. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +package org.eclipse.tractusx.ssi.lib.serialization.jwt; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class JwtConfig { + + private long expirationTime; +} diff --git a/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtPresentationFactory.java b/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtPresentationFactory.java index 9ebd457f..c62cf9fa 100644 --- a/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtPresentationFactory.java +++ b/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtPresentationFactory.java @@ -1,6 +1,6 @@ /* * ****************************************************************************** - * Copyright (c) 2021,2023 Contributors to the Eclipse Foundation + * Copyright (c) 2021,2024 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -29,6 +29,7 @@ /** The interface Serialized jwt presentation factory. */ public interface SerializedJwtPresentationFactory { + /** * Create presentation signed jwt. * @@ -39,5 +40,17 @@ public interface SerializedJwtPresentationFactory { * @return the signed jwt */ SignedJWT createPresentation( - Did issuer, List credentials, String audience, IPrivateKey privateKey); + Did issuer, + List credentials, + String audience, + IPrivateKey privateKey, + String keyId); + + SignedJWT createPresentation( + Did issuer, + List credentials, + String audience, + IPrivateKey privateKey, + String keyId, + JwtConfig config); } diff --git a/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtPresentationFactoryImpl.java b/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtPresentationFactoryImpl.java index c1f73a1f..e7d314da 100644 --- a/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtPresentationFactoryImpl.java +++ b/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtPresentationFactoryImpl.java @@ -1,6 +1,5 @@ -/* - * ****************************************************************************** - * Copyright (c) 2021,2023 Contributors to the Eclipse Foundation +/******************************************************************************** + * Copyright (c) 2021,2024 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -16,8 +15,7 @@ * under the License. * * SPDX-License-Identifier: Apache-2.0 - * ******************************************************************************* - */ + ********************************************************************************/ package org.eclipse.tractusx.ssi.lib.serialization.jwt; @@ -40,12 +38,44 @@ public class SerializedJwtPresentationFactoryImpl implements SerializedJwtPresentationFactory { private final SignedJwtFactory signedJwtFactory; + private final JsonLdSerializer jsonLdSerializer; + private final Did agentDid; @Override public SignedJWT createPresentation( - Did issuer, List credentials, String audience, IPrivateKey privateKey) { + Did issuer, + List credentials, + String audience, + IPrivateKey privateKey, + String keyId) { + + SerializedVerifiablePresentation serializedVerifiablePresentation = + buildSerializedPresentation(credentials); + + return signedJwtFactory.create( + issuer, audience, serializedVerifiablePresentation, privateKey, keyId); + } + + @Override + public SignedJWT createPresentation( + Did issuer, + List credentials, + String audience, + IPrivateKey privateKey, + String keyId, + JwtConfig config) { + + SerializedVerifiablePresentation serializedVerifiablePresentation = + buildSerializedPresentation(credentials); + + return signedJwtFactory.create( + issuer, audience, serializedVerifiablePresentation, privateKey, keyId, config); + } + + private SerializedVerifiablePresentation buildSerializedPresentation( + List credentials) { final VerifiablePresentationBuilder verifiablePresentationBuilder = new VerifiablePresentationBuilder(); final VerifiablePresentation verifiablePresentation = @@ -59,13 +89,6 @@ public SignedJWT createPresentation( .verifiableCredentials(credentials) .build(); - final SerializedVerifiablePresentation serializedVerifiablePresentation = - jsonLdSerializer.serializePresentation(verifiablePresentation); - return signedJwtFactory.create( - verifiablePresentation.getId(), - issuer, - audience, - serializedVerifiablePresentation, - privateKey); + return jsonLdSerializer.serializePresentation(verifiablePresentation); } } diff --git a/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtVCFactory.java b/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtVCFactory.java new file mode 100644 index 00000000..45b7b6a8 --- /dev/null +++ b/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtVCFactory.java @@ -0,0 +1,38 @@ +/* + * ****************************************************************************** + * Copyright (c) 2021,2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * 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. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ******************************************************************************* + */ + +package org.eclipse.tractusx.ssi.lib.serialization.jwt; + +import com.nimbusds.jwt.SignedJWT; +import java.util.Date; +import org.eclipse.tractusx.ssi.lib.crypt.IPrivateKey; +import org.eclipse.tractusx.ssi.lib.model.did.Did; +import org.eclipse.tractusx.ssi.lib.model.verifiable.credential.VerifiableCredential; + +public interface SerializedJwtVCFactory { + SignedJWT createVCJwt( + Did issuer, + Did holder, + Date expDate, + VerifiableCredential credentials, + IPrivateKey privateKey, + String keyId); +} diff --git a/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtVCFactoryImpl.java b/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtVCFactoryImpl.java new file mode 100644 index 00000000..677de028 --- /dev/null +++ b/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtVCFactoryImpl.java @@ -0,0 +1,49 @@ +/* + * ****************************************************************************** + * Copyright (c) 2021,2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * 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. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ******************************************************************************* + */ + +package org.eclipse.tractusx.ssi.lib.serialization.jwt; + +import com.nimbusds.jwt.SignedJWT; +import java.util.Date; +import java.util.LinkedHashMap; +import lombok.RequiredArgsConstructor; +import org.eclipse.tractusx.ssi.lib.crypt.IPrivateKey; +import org.eclipse.tractusx.ssi.lib.jwt.SignedJwtFactory; +import org.eclipse.tractusx.ssi.lib.model.did.Did; +import org.eclipse.tractusx.ssi.lib.model.verifiable.credential.VerifiableCredential; + +@RequiredArgsConstructor +public class SerializedJwtVCFactoryImpl implements SerializedJwtVCFactory { + private final SignedJwtFactory signedJwtFactory; + + @Override + public SignedJWT createVCJwt( + Did issuer, + Did holder, + Date expDate, + VerifiableCredential credentials, + IPrivateKey privateKey, + String keyId) { + var clonedVC = new LinkedHashMap(); + clonedVC.putAll(credentials); + return signedJwtFactory.create(issuer, holder, expDate, clonedVC, privateKey, keyId); + } +} diff --git a/src/test/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtPresentationFactoryImplTest.java b/src/test/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtPresentationFactoryImplTest.java index c76229d5..608e13e6 100644 --- a/src/test/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtPresentationFactoryImplTest.java +++ b/src/test/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtPresentationFactoryImplTest.java @@ -1,31 +1,8 @@ -/* - * ****************************************************************************** - * Copyright (c) 2021,2023 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * 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. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ******************************************************************************* - */ - package org.eclipse.tractusx.ssi.lib.serialization.jwt; -import com.nimbusds.jwt.JWTClaimsSet; import com.nimbusds.jwt.SignedJWT; import java.net.URI; import java.util.List; -import java.util.Map; import lombok.SneakyThrows; import org.eclipse.tractusx.ssi.lib.SsiLibrary; import org.eclipse.tractusx.ssi.lib.crypt.octet.OctetKeyPairFactory; @@ -44,24 +21,30 @@ import org.eclipse.tractusx.ssi.lib.util.identity.TestIdentityFactory; import org.eclipse.tractusx.ssi.lib.util.vc.TestVerifiableFactory; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; /** The type Serialized jwt presentation factory impl test. */ class SerializedJwtPresentationFactoryImplTest { - private LinkedDataProofGenerator linkedDataProofGenerator; + public static final int CUSTOM_EXPIRATION_TIME = 900; - private TestIdentity credentialIssuer; - private TestDidResolver didResolver; + public static final int DEFAULT_EXPIRATION_TIME = 60; - private SignedJwtVerifier jwtVerifier; + private static LinkedDataProofGenerator linkedDataProofGenerator; - /** Test jwt serialization. */ + private static TestIdentity credentialIssuer; + + private static TestDidResolver didResolver; + + private static SignedJwtVerifier jwtVerifier; + + @BeforeAll @SneakyThrows - @Test - public void testJwtSerialization() { + public static void beforeAll() { SsiLibrary.initialize(); - this.didResolver = new TestDidResolver(); + + didResolver = new TestDidResolver(); credentialIssuer = TestIdentityFactory.newIdentityWithED25519Keys(); didResolver.register(credentialIssuer); @@ -73,20 +56,42 @@ public void testJwtSerialization() { new LinkedDataHasher(), new LinkedDataTransformer(), new Ed25519ProofSigner()); + } - // prepare key - final URI verificationMethod = - credentialIssuer.getDidDocument().getVerificationMethods().get(0).getId(); + /** Test jwt serialization. */ + @SneakyThrows + @Test + void testJwtSerializationWithDefaultExpiration() { - final VerifiableCredential credential = - TestVerifiableFactory.createVerifiableCredential(credentialIssuer, null); + SerializedJwtPresentationFactory presentationFactory = + new SerializedJwtPresentationFactoryImpl( + new SignedJwtFactory(new OctetKeyPairFactory()), + new JsonLdSerializerImpl(), + credentialIssuer.getDid()); - final Proof proof = - linkedDataProofGenerator.createProof( - credential, verificationMethod, credentialIssuer.getPrivateKey()); + VerifiableCredential credentialWithProof = getCredential(); + + // Build JWT + SignedJWT presentation = + presentationFactory.createPresentation( + credentialIssuer.getDid(), + List.of(credentialWithProof), + "test-audience", + credentialIssuer.getPrivateKey(), + "key-2"); - final VerifiableCredential credentialWithProof = - TestVerifiableFactory.createVerifiableCredential(credentialIssuer, proof); + Assertions.assertNotNull(presentation); + Assertions.assertDoesNotThrow(() -> jwtVerifier.verify(presentation)); + Assertions.assertEquals( + DEFAULT_EXPIRATION_TIME, + (presentation.getJWTClaimsSet().getExpirationTime().getTime() + - presentation.getJWTClaimsSet().getIssueTime().getTime()) + / 1000); + } + + @SneakyThrows + @Test + void testJwtSerializationWithCustomExpiration() { SerializedJwtPresentationFactory presentationFactory = new SerializedJwtPresentationFactoryImpl( @@ -94,19 +99,42 @@ public void testJwtSerialization() { new JsonLdSerializerImpl(), credentialIssuer.getDid()); + VerifiableCredential credentialWithProof = getCredential(); + + JwtConfig jwtConfig = JwtConfig.builder().expirationTime(CUSTOM_EXPIRATION_TIME).build(); + // Build JWT SignedJWT presentation = presentationFactory.createPresentation( credentialIssuer.getDid(), List.of(credentialWithProof), "test-audience", - credentialIssuer.getPrivateKey()); + credentialIssuer.getPrivateKey(), + "key-2", + jwtConfig); Assertions.assertNotNull(presentation); Assertions.assertDoesNotThrow(() -> jwtVerifier.verify(presentation)); - JWTClaimsSet jwtClaimsSet = presentation.getJWTClaimsSet(); - Map vp = jwtClaimsSet.getJSONObjectClaim("vp"); + Assertions.assertEquals( + CUSTOM_EXPIRATION_TIME, + (presentation.getJWTClaimsSet().getExpirationTime().getTime() + - presentation.getJWTClaimsSet().getIssueTime().getTime()) + / 1000); + } + + @SneakyThrows + private VerifiableCredential getCredential() { + // prepare key + final URI verificationMethod = + credentialIssuer.getDidDocument().getVerificationMethods().get(0).getId(); + + final VerifiableCredential credential = + TestVerifiableFactory.createVerifiableCredential(credentialIssuer, null); + + final Proof proof = + linkedDataProofGenerator.createProof( + credential, verificationMethod, credentialIssuer.getPrivateKey()); - Assertions.assertEquals(vp.get("id"), jwtClaimsSet.getJWTID()); + return TestVerifiableFactory.createVerifiableCredential(credentialIssuer, proof); } } From 285733317f435c6fbbb09ca36be48179eb0ab543 Mon Sep 17 00:00:00 2001 From: Mustafa Alsalfiti Date: Tue, 27 Feb 2024 14:44:14 +0100 Subject: [PATCH 02/15] fix: exception names --- src/main/java/org/eclipse/tractusx/ssi/examples/VC.java | 4 ++-- .../tractusx/ssi/lib/crypt/x25519/x25519PrivateKey.java | 4 ++-- .../tractusx/ssi/lib/crypt/x25519/x25519PublicKey.java | 4 ++-- .../java/org/eclipse/tractusx/ssi/lib/proof/ISigner.java | 2 +- .../tractusx/ssi/lib/proof/LinkedDataProofGenerator.java | 2 +- .../tractusx/ssi/lib/cypto/ed21995/ed25519KeyTest.java | 4 ++-- .../eclipse/tractusx/ssi/lib/proof/SignAndVerifyTest.java | 8 ++++---- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/eclipse/tractusx/ssi/examples/VC.java b/src/main/java/org/eclipse/tractusx/ssi/examples/VC.java index 9bb6e3c2..6fc39052 100644 --- a/src/main/java/org/eclipse/tractusx/ssi/examples/VC.java +++ b/src/main/java/org/eclipse/tractusx/ssi/examples/VC.java @@ -80,7 +80,7 @@ public static VerifiableCredential createVCWithoutProof() { * @return the verifiable credential * @throws UnsupportedSignatureTypeException the unsupported signature type exception * @throws SsiException the ssi exception - * @throws InvalidePrivateKeyFormat the invalide private key format + * @throws InvalidPrivateKeyFormatException the invalide private key format */ public static VerifiableCredential createVCWithED25519Proof( VerifiableCredential credential, IPrivateKey privateKey, Did issuer) @@ -120,7 +120,7 @@ public static VerifiableCredential createVCWithED25519Proof( * @return the verifiable credential * @throws UnsupportedSignatureTypeException the unsupported signature type exception * @throws SsiException the ssi exception - * @throws InvalidePrivateKeyFormat the invalide private key format + * @throws InvalidPrivateKeyFormatException the invalide private key format */ public static VerifiableCredential createVCWithJWSProof( VerifiableCredential credential, IPrivateKey privateKey, Did issuer) diff --git a/src/main/java/org/eclipse/tractusx/ssi/lib/crypt/x25519/x25519PrivateKey.java b/src/main/java/org/eclipse/tractusx/ssi/lib/crypt/x25519/x25519PrivateKey.java index 24709425..a054743e 100644 --- a/src/main/java/org/eclipse/tractusx/ssi/lib/crypt/x25519/x25519PrivateKey.java +++ b/src/main/java/org/eclipse/tractusx/ssi/lib/crypt/x25519/x25519PrivateKey.java @@ -46,7 +46,7 @@ public class x25519PrivateKey implements IPrivateKey { * Instantiates a new X 25519 private key. * * @param privateKey the private key - * @throws InvalidePrivateKeyFormat the invalide private key format + * @throws InvalidPrivateKeyFormatException the invalide private key format */ public x25519PrivateKey(byte[] privateKey) throws InvalidPrivateKeyFormatException { if (this.getKeyLength() != privateKey.length) { @@ -60,7 +60,7 @@ public x25519PrivateKey(byte[] privateKey) throws InvalidPrivateKeyFormatExcepti * * @param privateKey the private key * @param pemFormat the pem format - * @throws InvalidePrivateKeyFormat the invalide private key format + * @throws InvalidPrivateKeyFormatException the invalide private key format * @throws IOException the io exception */ public x25519PrivateKey(String privateKey, boolean PEMFormat) diff --git a/src/main/java/org/eclipse/tractusx/ssi/lib/crypt/x25519/x25519PublicKey.java b/src/main/java/org/eclipse/tractusx/ssi/lib/crypt/x25519/x25519PublicKey.java index b0646aa0..7601ffe5 100644 --- a/src/main/java/org/eclipse/tractusx/ssi/lib/crypt/x25519/x25519PublicKey.java +++ b/src/main/java/org/eclipse/tractusx/ssi/lib/crypt/x25519/x25519PublicKey.java @@ -46,7 +46,7 @@ public class x25519PublicKey implements IPublicKey { * Instantiates a new X 25519 public key. * * @param publicKey the public key - * @throws InvalidePublicKeyFormat the invalide public key format + * @throws InvalidPublicKeyFormatException the invalide public key format */ public x25519PublicKey(byte[] publicKey) throws InvalidPublicKeyFormatException { if (this.getKeyLength() != publicKey.length) { @@ -60,7 +60,7 @@ public x25519PublicKey(byte[] publicKey) throws InvalidPublicKeyFormatException * * @param publicKey the public key * @param pemFormat the pe mformat - * @throws InvalidePublicKeyFormat the invalide public key format + * @throws InvalidPublicKeyFormatException the invalide public key format * @throws IOException the io exception */ public x25519PublicKey(String publicKey, boolean PEMformat) diff --git a/src/main/java/org/eclipse/tractusx/ssi/lib/proof/ISigner.java b/src/main/java/org/eclipse/tractusx/ssi/lib/proof/ISigner.java index c6d26170..2c978255 100644 --- a/src/main/java/org/eclipse/tractusx/ssi/lib/proof/ISigner.java +++ b/src/main/java/org/eclipse/tractusx/ssi/lib/proof/ISigner.java @@ -35,7 +35,7 @@ public interface ISigner { * @param privateKey the private key * @return the byte [ ] * @throws SsiException the ssi exception - * @throws InvalidePrivateKeyFormat the invalide private key format + * @throws InvalidPrivateKeyFormatException the invalide private key format */ public byte[] sign(HashedLinkedData hashedLinkedData, IPrivateKey privateKey) throws InvalidPrivateKeyFormatException, SignatureGenerateFailedException; diff --git a/src/main/java/org/eclipse/tractusx/ssi/lib/proof/LinkedDataProofGenerator.java b/src/main/java/org/eclipse/tractusx/ssi/lib/proof/LinkedDataProofGenerator.java index 44c0750d..d7ccc870 100644 --- a/src/main/java/org/eclipse/tractusx/ssi/lib/proof/LinkedDataProofGenerator.java +++ b/src/main/java/org/eclipse/tractusx/ssi/lib/proof/LinkedDataProofGenerator.java @@ -83,7 +83,7 @@ public static LinkedDataProofGenerator newInstance(SignatureType type) * @param privateKey the private key * @return the proof * @throws SsiException the ssi exception - * @throws InvalidePrivateKeyFormat the invalide private key format + * @throws InvalidPrivateKeyFormatException the invalide private key format */ public Proof createProof(Verifiable verifiable, URI verificationMethodId, IPrivateKey privateKey) throws InvalidPrivateKeyFormatException, SignatureGenerateFailedException, diff --git a/src/test/java/org/eclipse/tractusx/ssi/lib/cypto/ed21995/ed25519KeyTest.java b/src/test/java/org/eclipse/tractusx/ssi/lib/cypto/ed21995/ed25519KeyTest.java index 225a3053..4a50dafc 100644 --- a/src/test/java/org/eclipse/tractusx/ssi/lib/cypto/ed21995/ed25519KeyTest.java +++ b/src/test/java/org/eclipse/tractusx/ssi/lib/cypto/ed21995/ed25519KeyTest.java @@ -80,8 +80,8 @@ public void testED21559KeySerliztion() throws KeyGenerationException, IOExceptio * * @throws KeyGenerationException the key generation exception * @throws IOException the io exception - * @throws InvalidePrivateKeyFormat the invalide private key format - * @throws InvalidePublicKeyFormat the invalide public key format + * @throws InvalidPrivateKeyFormatException the invalide private key format + * @throws InvalidPublicKeyFormatException the invalide public key format */ @Test @SneakyThrows diff --git a/src/test/java/org/eclipse/tractusx/ssi/lib/proof/SignAndVerifyTest.java b/src/test/java/org/eclipse/tractusx/ssi/lib/proof/SignAndVerifyTest.java index 2afd0707..39da15d2 100644 --- a/src/test/java/org/eclipse/tractusx/ssi/lib/proof/SignAndVerifyTest.java +++ b/src/test/java/org/eclipse/tractusx/ssi/lib/proof/SignAndVerifyTest.java @@ -40,8 +40,8 @@ public class SignAndVerifyTest { * Test sign and verify ed 201559. * * @throws IOException the io exception - * @throws InvalidePrivateKeyFormat the invalide private key format - * @throws InvalidePublicKeyFormat the invalide public key format + * @throws InvalidPrivateKeyFormatException the invalide private key format + * @throws InvalidPublicKeyFormatException the invalide public key format * @throws KeyGenerationException the key generation exception */ @Test @@ -70,8 +70,8 @@ public void testSignAndVerify_ED201559() { * @throws IOException the io exception * @throws JOSEException the jose exception * @throws NoSuchAlgorithmException the no such algorithm exception - * @throws InvalidePrivateKeyFormat the invalide private key format - * @throws InvalidePublicKeyFormat the invalide public key format + * @throws InvalidPrivateKeyFormatException the invalide private key format + * @throws InvalidPublicKeyFormatException the invalide public key format * @throws KeyGenerationException the key generation exception */ @Test From 0d9091d3afc2e6f71a67417e2146bbd2ac644f95 Mon Sep 17 00:00:00 2001 From: Mustafa Alsalfiti Date: Tue, 27 Feb 2024 15:07:32 +0100 Subject: [PATCH 03/15] fix: exception name --- .../lib/exception/proof/NoVerificationKeyFoundException.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/eclipse/tractusx/ssi/lib/exception/proof/NoVerificationKeyFoundException.java b/src/main/java/org/eclipse/tractusx/ssi/lib/exception/proof/NoVerificationKeyFoundException.java index 36806c6e..0be78676 100644 --- a/src/main/java/org/eclipse/tractusx/ssi/lib/exception/proof/NoVerificationKeyFoundException.java +++ b/src/main/java/org/eclipse/tractusx/ssi/lib/exception/proof/NoVerificationKeyFoundException.java @@ -21,7 +21,7 @@ package org.eclipse.tractusx.ssi.lib.exception.proof; -/** NoVerificationKeyFoundExcpetion */ +/** NoVerificationKeyFoundException */ public class NoVerificationKeyFoundException extends SignatureVerificationException { private static final long serialVersionUID = 1L; /** From 2e9fa35317b99d34b606140f1bdaf2a72cf430c8 Mon Sep 17 00:00:00 2001 From: Mustafa Alsalfiti Date: Mon, 11 Mar 2024 13:52:48 +0100 Subject: [PATCH 04/15] fix: add iat to jwt --- .../eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java b/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java index 59ea8dab..e4699e60 100644 --- a/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java +++ b/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java @@ -29,13 +29,14 @@ import com.nimbusds.jose.jwk.OctetKeyPair; import com.nimbusds.jwt.JWTClaimsSet; import com.nimbusds.jwt.SignedJWT; +import java.time.Instant; import java.util.*; import java.util.stream.Collectors; import lombok.SneakyThrows; import org.eclipse.tractusx.ssi.lib.crypt.IPrivateKey; import org.eclipse.tractusx.ssi.lib.crypt.octet.OctetKeyPairFactory; import org.eclipse.tractusx.ssi.lib.model.did.Did; -import org.eclipse.tractusx.ssi.lib.model.verifiable.credential.VerifiableCredential; +import org.eclipse.tractusx.ssi.lib.model.verifiable.Verifiable; import org.eclipse.tractusx.ssi.lib.serialization.jwt.JwtConfig; import org.eclipse.tractusx.ssi.lib.serialization.jwt.SerializedVerifiablePresentation; @@ -130,7 +131,10 @@ public SignedJWT create( final String issuer = didIssuer.toString(); final String subject = holderIssuer.toString(); - vc.remove(VerifiableCredential.PROOF); + final Date issueDate = Date.from(Instant.parse((String) vc.get("issuanceDate"))); + + + vc.remove(Verifiable.PROOF); var claimsSet = new JWTClaimsSet.Builder() @@ -138,7 +142,7 @@ public SignedJWT create( .subject(subject) .claim("vc", vc) .expirationTime(expDate) - .jwtID(UUID.randomUUID().toString()) + .issueTime(issueDate) .build(); final OctetKeyPair octetKeyPair = octetKeyPairFactory.fromPrivateKey(privateKey); From d7923be35bdfcf0be045fd03911fc4dc0b287e64 Mon Sep 17 00:00:00 2001 From: Mustafa Alsalfiti Date: Mon, 11 Mar 2024 13:59:24 +0100 Subject: [PATCH 05/15] fix: apply spotless --- .../java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java b/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java index e4699e60..25a54008 100644 --- a/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java +++ b/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java @@ -133,7 +133,6 @@ public SignedJWT create( final Date issueDate = Date.from(Instant.parse((String) vc.get("issuanceDate"))); - vc.remove(Verifiable.PROOF); var claimsSet = From cf37c3119748cec3a4dd73f4d111854ed3dbe901 Mon Sep 17 00:00:00 2001 From: Mustafa Alsalfiti Date: Tue, 12 Mar 2024 14:08:42 +0100 Subject: [PATCH 06/15] fix: add null check for dates --- .../tractusx/ssi/lib/jwt/SignedJwtFactory.java | 15 ++++++++++++--- .../serialization/jwt/SerializedJwtVCFactory.java | 2 -- .../jwt/SerializedJwtVCFactoryImpl.java | 4 +--- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java b/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java index 25a54008..578c40a1 100644 --- a/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java +++ b/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java @@ -124,14 +124,23 @@ public SignedJWT create( public SignedJWT create( Did didIssuer, Did holderIssuer, - Date expDate, LinkedHashMap vc, IPrivateKey privateKey, String keyId) { final String issuer = didIssuer.toString(); final String subject = holderIssuer.toString(); - final Date issueDate = Date.from(Instant.parse((String) vc.get("issuanceDate"))); + // check if expirationDate is presented in VC then use it, otherwise null + final Date expireDateAsDate = + vc.containsKey("expirationDate") + ? Date.from(Instant.parse((String) vc.get("expirationDate"))) + : null; + + // check if issuanceDate is presented in VC then use it, otherwise null + final Date issueDate = + vc.containsKey("issuanceDate") + ? Date.from(Instant.parse((String) vc.get("issuanceDate"))) + : null; vc.remove(Verifiable.PROOF); @@ -140,7 +149,7 @@ public SignedJWT create( .issuer(issuer) .subject(subject) .claim("vc", vc) - .expirationTime(expDate) + .expirationTime(expireDateAsDate) .issueTime(issueDate) .build(); diff --git a/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtVCFactory.java b/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtVCFactory.java index 45b7b6a8..2a6c9767 100644 --- a/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtVCFactory.java +++ b/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtVCFactory.java @@ -22,7 +22,6 @@ package org.eclipse.tractusx.ssi.lib.serialization.jwt; import com.nimbusds.jwt.SignedJWT; -import java.util.Date; import org.eclipse.tractusx.ssi.lib.crypt.IPrivateKey; import org.eclipse.tractusx.ssi.lib.model.did.Did; import org.eclipse.tractusx.ssi.lib.model.verifiable.credential.VerifiableCredential; @@ -31,7 +30,6 @@ public interface SerializedJwtVCFactory { SignedJWT createVCJwt( Did issuer, Did holder, - Date expDate, VerifiableCredential credentials, IPrivateKey privateKey, String keyId); diff --git a/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtVCFactoryImpl.java b/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtVCFactoryImpl.java index 677de028..12c7497a 100644 --- a/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtVCFactoryImpl.java +++ b/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtVCFactoryImpl.java @@ -22,7 +22,6 @@ package org.eclipse.tractusx.ssi.lib.serialization.jwt; import com.nimbusds.jwt.SignedJWT; -import java.util.Date; import java.util.LinkedHashMap; import lombok.RequiredArgsConstructor; import org.eclipse.tractusx.ssi.lib.crypt.IPrivateKey; @@ -38,12 +37,11 @@ public class SerializedJwtVCFactoryImpl implements SerializedJwtVCFactory { public SignedJWT createVCJwt( Did issuer, Did holder, - Date expDate, VerifiableCredential credentials, IPrivateKey privateKey, String keyId) { var clonedVC = new LinkedHashMap(); clonedVC.putAll(credentials); - return signedJwtFactory.create(issuer, holder, expDate, clonedVC, privateKey, keyId); + return signedJwtFactory.create(issuer, holder, clonedVC, privateKey, keyId); } } From 5b2a0a303d6088fbc743304123974fd05d00e531 Mon Sep 17 00:00:00 2001 From: Mustafa Alsalfiti Date: Tue, 19 Mar 2024 11:49:33 +0100 Subject: [PATCH 07/15] fix: vp copyright --- .../org/eclipse/tractusx/ssi/examples/VP.java | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/eclipse/tractusx/ssi/examples/VP.java b/src/main/java/org/eclipse/tractusx/ssi/examples/VP.java index 0ee66ea9..0b7be409 100644 --- a/src/main/java/org/eclipse/tractusx/ssi/examples/VP.java +++ b/src/main/java/org/eclipse/tractusx/ssi/examples/VP.java @@ -1,21 +1,23 @@ -/******************************************************************************** - * Copyright (c) 2021,2024 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * 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. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ +/* +* ****************************************************************************** +* Copyright (c) 2021,2024 Contributors to the Eclipse Foundation +* +* See the NOTICE file(s) distributed with this work for additional +* information regarding copyright ownership. +* +* 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. +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +* License for the specific language governing permissions and limitations +* under the License. +* +* SPDX-License-Identifier: Apache-2.0 +* ******************************************************************************* +*/ package org.eclipse.tractusx.ssi.examples; From 4b7105db75dceb65c9043b5a4c33d686e4600685 Mon Sep 17 00:00:00 2001 From: Mustafa Alsalfiti Date: Tue, 19 Mar 2024 11:54:49 +0100 Subject: [PATCH 08/15] fix: apply spotless --- .../org/eclipse/tractusx/ssi/examples/VP.java | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/eclipse/tractusx/ssi/examples/VP.java b/src/main/java/org/eclipse/tractusx/ssi/examples/VP.java index 0b7be409..25a29c5f 100644 --- a/src/main/java/org/eclipse/tractusx/ssi/examples/VP.java +++ b/src/main/java/org/eclipse/tractusx/ssi/examples/VP.java @@ -1,23 +1,23 @@ /* -* ****************************************************************************** -* Copyright (c) 2021,2024 Contributors to the Eclipse Foundation -* -* See the NOTICE file(s) distributed with this work for additional -* information regarding copyright ownership. -* -* 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. -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -* License for the specific language governing permissions and limitations -* under the License. -* -* SPDX-License-Identifier: Apache-2.0 -* ******************************************************************************* -*/ + * ****************************************************************************** + * Copyright (c) 2021,2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * 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. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ******************************************************************************* + */ package org.eclipse.tractusx.ssi.examples; From 15b9a138d0a1d895b81161f31af8cd4b40b56fe9 Mon Sep 17 00:00:00 2001 From: Mustafa Alsalfiti Date: Tue, 19 Mar 2024 13:22:04 +0100 Subject: [PATCH 09/15] fix: add test --- .../jwt/SignedJwtFactoryTest.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/test/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SignedJwtFactoryTest.java diff --git a/src/test/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SignedJwtFactoryTest.java b/src/test/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SignedJwtFactoryTest.java new file mode 100644 index 00000000..562f4591 --- /dev/null +++ b/src/test/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SignedJwtFactoryTest.java @@ -0,0 +1,47 @@ +package org.eclipse.tractusx.ssi.lib.serialization.jwt; + +import static org.junit.Assert.assertNotNull; + +import com.nimbusds.jwt.SignedJWT; +import java.util.LinkedHashMap; +import org.eclipse.tractusx.ssi.lib.SsiLibrary; +import org.eclipse.tractusx.ssi.lib.crypt.octet.OctetKeyPairFactory; +import org.eclipse.tractusx.ssi.lib.jwt.SignedJwtFactory; +import org.eclipse.tractusx.ssi.lib.util.identity.TestIdentity; +import org.eclipse.tractusx.ssi.lib.util.identity.TestIdentityFactory; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class SignedJwtFactoryTest { + + private static TestIdentity credentialIssuer; + + @BeforeAll + public static void beforeAll() { + SsiLibrary.initialize(); + credentialIssuer = TestIdentityFactory.newIdentityWithED25519Keys(); + } + + @Test + @DisplayName( + "Should return a signed Jwt with the given Map of claims and the given private key.") + void shouldReturnSignedJWT() { + + LinkedHashMap claims = new LinkedHashMap<>(); + SignedJwtFactory signedJwtFactory = new SignedJwtFactory(new OctetKeyPairFactory()); + String keyId = "key-1"; + // When + + SignedJWT signedJWT = + signedJwtFactory.create( + credentialIssuer.getDid(), + credentialIssuer.getDid(), + claims, + credentialIssuer.getPrivateKey(), + keyId); + + // Then + assertNotNull(signedJWT); + } +} From 55a9b4439152579e9a9564943695863657714919 Mon Sep 17 00:00:00 2001 From: Mustafa Alsalfiti Date: Tue, 19 Mar 2024 13:22:29 +0100 Subject: [PATCH 10/15] fix: apply spotless --- .../ssi/lib/serialization/jwt/SignedJwtFactoryTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SignedJwtFactoryTest.java b/src/test/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SignedJwtFactoryTest.java index 562f4591..f1f9311c 100644 --- a/src/test/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SignedJwtFactoryTest.java +++ b/src/test/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SignedJwtFactoryTest.java @@ -24,8 +24,7 @@ public static void beforeAll() { } @Test - @DisplayName( - "Should return a signed Jwt with the given Map of claims and the given private key.") + @DisplayName("Should return a signed Jwt with the given Map of claims and the given private key.") void shouldReturnSignedJWT() { LinkedHashMap claims = new LinkedHashMap<>(); From bf37656a79689b20992458d0d7ba1b90d99e315a Mon Sep 17 00:00:00 2001 From: Mustafa Alsalfiti Date: Tue, 16 Apr 2024 11:26:38 +0200 Subject: [PATCH 11/15] fix: resolve comments --- DEPENDENCIES | 4 -- .../org/eclipse/tractusx/ssi/examples/VP.java | 13 +++-- .../ssi/lib/jwt/SignedJwtFactory.java | 55 +++++++++++++------ .../ssi/lib/serialization/jwt/JwtConfig.java | 2 +- .../jwt/SerializedJwtPresentationFactory.java | 12 ++++ ...ializedJwtPresentationFactoryImplTest.java | 21 +++++++ 6 files changed, 80 insertions(+), 27 deletions(-) diff --git a/DEPENDENCIES b/DEPENDENCIES index 42482842..80b52a6f 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -24,10 +24,6 @@ maven/mavencentral/net.i2p.crypto/eddsa/0.3.0, CC0-1.0, approved, CQ22537 maven/mavencentral/org.apache.commons/commons-lang3/3.14.0, Apache-2.0, approved, #11677 maven/mavencentral/org.bouncycastle/bcprov-jdk18on/1.77, MIT AND CC0-1.0, approved, #11595 maven/mavencentral/org.checkerframework/checker-qual/3.37.0, MIT, approved, clearlydefined -maven/mavencentral/org.apache.commons/commons-lang3/3.12.0, Apache-2.0, approved, clearlydefined -maven/mavencentral/org.apache.httpcomponents/httpclient/4.5.14, Apache-2.0 AND LicenseRef-Public-Domain, approved, CQ23527 -maven/mavencentral/org.apache.httpcomponents/httpcore/4.4.16, Apache-2.0, approved, CQ23528 -maven/mavencentral/org.checkerframework/checker-compat-qual/2.5.5, GPL-2.0-only with Classpath-Exception-2.0, approved, #11598 maven/mavencentral/org.codehaus.woodstox/stax2-api/4.2.1, BSD-2-Clause, approved, #2670 maven/mavencentral/org.eclipse.parsson/parsson/1.1.5, EPL-2.0, approved, ee4j.parsson maven/mavencentral/org.projectlombok/lombok/1.18.30, MIT AND LicenseRef-Public-Domain, approved, CQ23907 diff --git a/src/main/java/org/eclipse/tractusx/ssi/examples/VP.java b/src/main/java/org/eclipse/tractusx/ssi/examples/VP.java index 25a29c5f..a5ecc382 100644 --- a/src/main/java/org/eclipse/tractusx/ssi/examples/VP.java +++ b/src/main/java/org/eclipse/tractusx/ssi/examples/VP.java @@ -21,9 +21,9 @@ package org.eclipse.tractusx.ssi.examples; -import com.nimbusds.jwt.SignedJWT; import java.io.IOException; import java.util.List; + import org.eclipse.tractusx.ssi.lib.crypt.IPrivateKey; import org.eclipse.tractusx.ssi.lib.crypt.IPublicKey; import org.eclipse.tractusx.ssi.lib.crypt.octet.OctetKeyPairFactory; @@ -37,12 +37,13 @@ import org.eclipse.tractusx.ssi.lib.serialization.jwt.SerializedJwtPresentationFactory; import org.eclipse.tractusx.ssi.lib.serialization.jwt.SerializedJwtPresentationFactoryImpl; +import com.nimbusds.jwt.SignedJWT; + /** * This is an example class to demonstrate how to create a Verifiable Presentation in JSON-LD and * JWT format */ class VP { - /** * Create a verifiable presentation. * @@ -63,7 +64,7 @@ public static VerifiablePresentation createVP( return verifiablePresentation; } - /** + /** * Create vp as a signed jwt. * * @param issuer the issuer @@ -71,6 +72,7 @@ public static VerifiablePresentation createVP( * @param audience the audience * @param privateKey the private key * @param publicKey the public key + * @param keyId the key id * @return the signed jwt * @throws IOException the io exception */ @@ -79,7 +81,8 @@ public static SignedJWT createVPAsJWT( List credentials, String audience, IPrivateKey privateKey, - IPublicKey publicKey) + IPublicKey publicKey, + String keyId) throws IOException { // Extracting keys @@ -91,6 +94,6 @@ public static SignedJWT createVPAsJWT( new SignedJwtFactory(new OctetKeyPairFactory()), new JsonLdSerializerImpl(), issuer); return presentationFactory.createPresentation( - issuer, credentials, audience, privateKey, "keyId"); + issuer, credentials, audience, privateKey, keyId); } } diff --git a/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java b/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java index 578c40a1..72c9fb1b 100644 --- a/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java +++ b/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java @@ -41,8 +41,8 @@ import org.eclipse.tractusx.ssi.lib.serialization.jwt.SerializedVerifiablePresentation; /** - * Convenience/helper class to generate * Convenience/helper class to generate and verify Signed - * JSON Web Tokens (JWTs) for communicating between connector instances. + * Convenience/helper class to generate and verify Signed JSON Web Tokens (JWTs) for communicating + * between connector instances. */ public class SignedJwtFactory { @@ -53,14 +53,15 @@ public SignedJwtFactory(OctetKeyPairFactory octetKeyPairFactory) { } /** - * Creates a signed JWT {@link SignedJWT} that contains a set of claims and an issuer. Although - * all private key types are possible, in the context of Distributed Identity using an Elliptic - * Curve key ({@code P-256}) is advisable. + * Creates a signed JWT {@link SignedJWT} that contains a set of claims and an issuer with a + * default configuration (60 second expiration time) {@link JwtConfig} for VP * - * @param audience the value of the token audience claim, e.g. the IDS Webhook address. - * @param keyId the id of the key, the kid of the jws-header will be constructed via - * +"#"+ - * @return a {@code SignedJWT} that is signed with the private key and contains all claims listed. + * @param didIssuer + * @param audience + * @param serializedPresentation + * @param privateKey + * @param keyId + * @return */ @SneakyThrows public SignedJWT create( @@ -74,15 +75,16 @@ public SignedJWT create( } /** - * Creates a signed JWT {@link SignedJWT} that contains a set of claims and an issuer. Although - * all private key types are possible, in the context of Distributed Identity using an Elliptic - * Curve key ({@code P-256}) is advisable. + * Creates a signed JWT {@link SignedJWT} that contains a set of claims and an issuer with a + * specific configuration {@link JwtConfig} for VP * - * @param audience the value of the token audience claim, e.g. the IDS Webhook address. - * @param keyId the id of the key, the kid of the jws-header will be constructed via - * +"#"+ - * @param config the custom configuration for the JWT to create, e.g. custom expiration time (exp) - * @return a {@code SignedJWT} that is signed with the private key and contains all claims listed. + * @param didIssuer + * @param audience + * @param serializedPresentation + * @param privateKey + * @param keyId + * @param config + * @return */ @SneakyThrows public SignedJWT create( @@ -120,6 +122,16 @@ public SignedJWT create( return createSignedES256Jwt(octetKeyPair, claimsSet, issuer, keyId); } + /** + * Creates a signed JWT {@link SignedJWT} from a Verifiable Credential + * + * @param didIssuer + * @param holderIssuer + * @param vc + * @param privateKey + * @param keyId + * @return + */ @SneakyThrows public SignedJWT create( Did didIssuer, @@ -157,6 +169,15 @@ public SignedJWT create( return createSignedES256Jwt(octetKeyPair, claimsSet, issuer, keyId); } + /** + * Create a signedJwt for ES256 JWT {@link SignedJWT} with a set of claims + * + * @param privateKey + * @param claimsSet + * @param issuer + * @param keyId + * @return + */ public SignedJWT createSignedES256Jwt( OctetKeyPair privateKey, JWTClaimsSet claimsSet, String issuer, String keyId) { JWSSigner signer; diff --git a/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/JwtConfig.java b/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/JwtConfig.java index 7d45c369..06264907 100644 --- a/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/JwtConfig.java +++ b/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/JwtConfig.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2021,2023 Contributors to the Eclipse Foundation + * Copyright (c) 2021,2024 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. diff --git a/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtPresentationFactory.java b/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtPresentationFactory.java index c62cf9fa..f9515d4e 100644 --- a/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtPresentationFactory.java +++ b/src/main/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtPresentationFactory.java @@ -37,6 +37,7 @@ public interface SerializedJwtPresentationFactory { * @param credentials the credentials * @param audience the audience * @param privateKey the private key + * @param keyId the key id * @return the signed jwt */ SignedJWT createPresentation( @@ -46,6 +47,17 @@ SignedJWT createPresentation( IPrivateKey privateKey, String keyId); + /** + * Create presentation signed jwt. + * + * @param issuer the issuer + * @param credentials the credentials + * @param audience the audience + * @param privateKey the private key + * @param keyId the key id + * @param config jwt config + * @return the signed jwt + */ SignedJWT createPresentation( Did issuer, List credentials, diff --git a/src/test/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtPresentationFactoryImplTest.java b/src/test/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtPresentationFactoryImplTest.java index 608e13e6..03c4e017 100644 --- a/src/test/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtPresentationFactoryImplTest.java +++ b/src/test/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SerializedJwtPresentationFactoryImplTest.java @@ -1,3 +1,24 @@ +/* + * ****************************************************************************** + * Copyright (c) 2021,2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * 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. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ******************************************************************************* + */ + package org.eclipse.tractusx.ssi.lib.serialization.jwt; import com.nimbusds.jwt.SignedJWT; From 78c4728be7eb61358117aa21fb594b6d14175260 Mon Sep 17 00:00:00 2001 From: Mustafa Alsalfiti Date: Tue, 16 Apr 2024 11:27:01 +0200 Subject: [PATCH 12/15] fix: apply spotless --- src/main/java/org/eclipse/tractusx/ssi/examples/VP.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/eclipse/tractusx/ssi/examples/VP.java b/src/main/java/org/eclipse/tractusx/ssi/examples/VP.java index a5ecc382..56f93312 100644 --- a/src/main/java/org/eclipse/tractusx/ssi/examples/VP.java +++ b/src/main/java/org/eclipse/tractusx/ssi/examples/VP.java @@ -21,9 +21,9 @@ package org.eclipse.tractusx.ssi.examples; +import com.nimbusds.jwt.SignedJWT; import java.io.IOException; import java.util.List; - import org.eclipse.tractusx.ssi.lib.crypt.IPrivateKey; import org.eclipse.tractusx.ssi.lib.crypt.IPublicKey; import org.eclipse.tractusx.ssi.lib.crypt.octet.OctetKeyPairFactory; @@ -37,8 +37,6 @@ import org.eclipse.tractusx.ssi.lib.serialization.jwt.SerializedJwtPresentationFactory; import org.eclipse.tractusx.ssi.lib.serialization.jwt.SerializedJwtPresentationFactoryImpl; -import com.nimbusds.jwt.SignedJWT; - /** * This is an example class to demonstrate how to create a Verifiable Presentation in JSON-LD and * JWT format @@ -64,7 +62,7 @@ public static VerifiablePresentation createVP( return verifiablePresentation; } - /** + /** * Create vp as a signed jwt. * * @param issuer the issuer @@ -93,7 +91,6 @@ public static SignedJWT createVPAsJWT( new SerializedJwtPresentationFactoryImpl( new SignedJwtFactory(new OctetKeyPairFactory()), new JsonLdSerializerImpl(), issuer); - return presentationFactory.createPresentation( - issuer, credentials, audience, privateKey, keyId); + return presentationFactory.createPresentation(issuer, credentials, audience, privateKey, keyId); } } From c8c2e0d3416ea26d112fb15d45b9f5a056738f79 Mon Sep 17 00:00:00 2001 From: Mustafa Alsalfiti Date: Tue, 16 Apr 2024 12:46:48 +0200 Subject: [PATCH 13/15] fix: add copyright in test and added assert to header --- .../jwt/SignedJwtFactoryTest.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/test/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SignedJwtFactoryTest.java b/src/test/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SignedJwtFactoryTest.java index f1f9311c..310e764b 100644 --- a/src/test/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SignedJwtFactoryTest.java +++ b/src/test/java/org/eclipse/tractusx/ssi/lib/serialization/jwt/SignedJwtFactoryTest.java @@ -1,7 +1,30 @@ +/* + * ****************************************************************************** + * Copyright (c) 2021,2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * 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. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ******************************************************************************* + */ + package org.eclipse.tractusx.ssi.lib.serialization.jwt; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import com.nimbusds.jose.JWSAlgorithm; import com.nimbusds.jwt.SignedJWT; import java.util.LinkedHashMap; import org.eclipse.tractusx.ssi.lib.SsiLibrary; @@ -42,5 +65,9 @@ void shouldReturnSignedJWT() { // Then assertNotNull(signedJWT); + // check jwt is not empty + assertNotNull(signedJWT.serialize()); + // check jwt header + assertEquals(JWSAlgorithm.EdDSA, signedJWT.getHeader().getAlgorithm()); } } From 369adc07641d6c1a1a84534117f637c6ffd20058 Mon Sep 17 00:00:00 2001 From: Mustafa Alsalfiti Date: Tue, 16 Apr 2024 18:04:46 +0200 Subject: [PATCH 14/15] fix: change var name and remove IO exception --- .../tractusx/ssi/lib/crypt/x25519/x25519PrivateKey.java | 1 - .../org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/eclipse/tractusx/ssi/lib/crypt/x25519/x25519PrivateKey.java b/src/main/java/org/eclipse/tractusx/ssi/lib/crypt/x25519/x25519PrivateKey.java index a054743e..b27dd1d4 100644 --- a/src/main/java/org/eclipse/tractusx/ssi/lib/crypt/x25519/x25519PrivateKey.java +++ b/src/main/java/org/eclipse/tractusx/ssi/lib/crypt/x25519/x25519PrivateKey.java @@ -61,7 +61,6 @@ public x25519PrivateKey(byte[] privateKey) throws InvalidPrivateKeyFormatExcepti * @param privateKey the private key * @param pemFormat the pem format * @throws InvalidPrivateKeyFormatException the invalide private key format - * @throws IOException the io exception */ public x25519PrivateKey(String privateKey, boolean PEMFormat) throws InvalidPrivateKeyFormatException { diff --git a/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java b/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java index 72c9fb1b..727fada1 100644 --- a/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java +++ b/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java @@ -135,12 +135,12 @@ public SignedJWT create( @SneakyThrows public SignedJWT create( Did didIssuer, - Did holderIssuer, + Did holderDid, LinkedHashMap vc, IPrivateKey privateKey, String keyId) { final String issuer = didIssuer.toString(); - final String subject = holderIssuer.toString(); + final String subject = holderDid.toString(); // check if expirationDate is presented in VC then use it, otherwise null final Date expireDateAsDate = From 9e7d6c3f1677858fa0cc8781ca6d016d31f4a981 Mon Sep 17 00:00:00 2001 From: Mustafa Alsalfiti Date: Tue, 16 Apr 2024 19:40:59 +0200 Subject: [PATCH 15/15] fix: add base64URLEncodePayload to SignedJWT --- .../org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java b/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java index 727fada1..88080833 100644 --- a/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java +++ b/src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java @@ -195,7 +195,12 @@ public SignedJWT createSignedES256Jwt( var algorithm = JWSAlgorithm.EdDSA; var type = JOSEObjectType.JWT; - var header = new JWSHeader.Builder(algorithm).type(type).keyID(issuer + "#" + keyId).build(); + var header = + new JWSHeader.Builder(algorithm) + .type(type) + .keyID(issuer + "#" + keyId) + .base64URLEncodePayload(true) + .build(); var vc = new SignedJWT(header, claimsSet); vc.sign(signer);