Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Create VC as jwt( json web token) #91

Merged
merged 15 commits into from
Apr 17, 2024
Merged
4 changes: 0 additions & 4 deletions DEPENDENCIES
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 2 additions & 2 deletions src/main/java/org/eclipse/tractusx/ssi/examples/VC.java
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
9 changes: 5 additions & 4 deletions src/main/java/org/eclipse/tractusx/ssi/examples/VP.java
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -42,7 +42,6 @@
* JWT format
*/
class VP {

/**
* Create a verifiable presentation.
*
Expand Down Expand Up @@ -71,6 +70,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
*/
Expand All @@ -79,7 +79,8 @@ public static SignedJWT createVPAsJWT(
List<VerifiableCredential> credentials,
String audience,
IPrivateKey privateKey,
IPublicKey publicKey)
IPublicKey publicKey,
String keyId)
throws IOException {

// Extracting keys
Expand All @@ -90,6 +91,6 @@ 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -60,8 +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 IOException the io exception
* @throws InvalidPrivateKeyFormatException the invalide private key format
*/
public x25519PrivateKey(String privateKey, boolean PEMFormat)
throws InvalidPrivateKeyFormatException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
/**
Expand Down
148 changes: 114 additions & 34 deletions src/main/java/org/eclipse/tractusx/ssi/lib/jwt/SignedJwtFactory.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/*
* ******************************************************************************
/********************************************************************************
* Copyright (c) 2021,2024 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
Expand All @@ -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;
Expand All @@ -30,16 +29,15 @@
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.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.Verifiable;
import org.eclipse.tractusx.ssi.lib.serialization.jwt.JwtConfig;
import org.eclipse.tractusx.ssi.lib.serialization.jwt.SerializedVerifiablePresentation;

/**
Expand All @@ -50,57 +48,138 @@ 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 with a
* default configuration (60 second expiration time) {@link JwtConfig} for VP
*
* @param octetKeyPairFactory the octet key pair factory
* @param didIssuer
* @param audience
* @param serializedPresentation
* @param privateKey
* @param keyId
* @return
*/
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);
}

/**
* 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 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
* @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(
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<HashMap<String, Object>> typeRef =
new TypeReference<HashMap<String, Object>>() {};

// make on object out of it so that it can get serialized again
Map<String, Object> vp =
new ObjectMapper().readValue(serializedPresentation.getJson(), HashMap.class);
new ObjectMapper().readValue(serializedPresentation.getJson(), typeRef);

Date iat = new Date();

var claimsSet =
new JWTClaimsSet.Builder()
.issuer(issuer)
.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);
return createSignedES256Jwt(octetKeyPair, claimsSet, issuer, keyId);
}

private static SignedJWT createSignedES256Jwt(
OctetKeyPair privateKey, JWTClaimsSet claimsSet, String issuer) {
/**
* 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,
Did holderDid,
LinkedHashMap<String, Object> vc,
IPrivateKey privateKey,
String keyId) {
final String issuer = didIssuer.toString();
final String subject = holderDid.toString();

// 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);

var claimsSet =
new JWTClaimsSet.Builder()
.issuer(issuer)
.subject(subject)
.claim("vc", vc)
.expirationTime(expireDateAsDate)
.issueTime(issueDate)
.build();

final OctetKeyPair octetKeyPair = octetKeyPairFactory.fromPrivateKey(privateKey);
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;
try {

Expand All @@ -116,11 +195,12 @@ 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)
.base64URLEncodePayload(true)
.build();
var vc = new SignedJWT(header, claimsSet);

vc.sign(signer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +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 lombok.Builder;
import lombok.Getter;

@Getter
@Builder
public class JwtConfig {

private long expirationTime;
}
Loading
Loading