diff --git a/build.sbt b/build.sbt index 0cfb605dac..fc84ccc210 100644 --- a/build.sbt +++ b/build.sbt @@ -85,8 +85,6 @@ lazy val V = new { val zioPreludeVersion = "1.0.0-RC24" val apollo = "1.2.14" - val bouncyCastle = "1.78.1" - val jsonSchemaValidator = "1.3.2" // scala-steward:off //TODO 1.3.2 need to fix: // [error] org.hyperledger.identus.pollux.core.model.schema.AnoncredSchemaTypeSpec // [error] org.hyperledger.identus.pollux.core.model.schema.CredentialSchemaSpec diff --git a/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/PresentationServiceSpecHelper.scala b/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/PresentationServiceSpecHelper.scala index 558c24be92..7938a84631 100644 --- a/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/PresentationServiceSpecHelper.scala +++ b/pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/service/PresentationServiceSpecHelper.scala @@ -11,9 +11,8 @@ import org.hyperledger.identus.pollux.core.repository.* import org.hyperledger.identus.pollux.core.service.serdes.* import org.hyperledger.identus.pollux.vc.jwt.* import org.hyperledger.identus.shared.models.{WalletAccessContext, WalletId} +import org.hyperledger.identus.shared.crypto.KmpSecp256k1KeyOps import zio.* - -import java.security.* import java.time.Instant import java.util.UUID @@ -42,16 +41,16 @@ trait PresentationServiceSpecHelper { CredentialRepositoryInMemory.layer ) ++ defaultWalletLayer - def createIssuer(did: DID) = { - val keyGen = KeyPairGenerator.getInstance("EC") - keyGen.initialize(Curve.P_256.toECParameterSpec) - val keyPair = keyGen.generateKeyPair() - val privateKey = keyPair.getPrivate - val publicKey = keyPair.getPublic + def createIssuer(did: DID): Issuer = { + + val keyPair = KmpSecp256k1KeyOps.generateKeyPair + val javaSKey = keyPair.privateKey.toJavaPrivateKey + val javaPKey = keyPair.publicKey.toJavaPublicKey + Issuer( did = did, - signer = ES256Signer(privateKey), - publicKey = publicKey + signer = ES256KSigner(javaSKey), + publicKey = javaPKey ) } diff --git a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/DidJWT.scala b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/DidJWT.scala index 7b7c90fdf0..19bf145f9d 100644 --- a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/DidJWT.scala +++ b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/DidJWT.scala @@ -29,19 +29,6 @@ trait Signer { } -class ES256Signer(privateKey: PrivateKey) extends Signer { - val algorithm: JwtECDSAAlgorithm = JwtAlgorithm.ES256 - private val provider = BouncyCastleProviderSingleton.getInstance - Security.addProvider(provider) - - override def encode(claim: Json): JWT = JWT(JwtCirce.encode(claim, privateKey, algorithm)) - - override def generateProofForJson(payload: Json, pk: PublicKey): Task[Proof] = { - EddsaJcs2022ProofGenerator.generateProof(payload, privateKey, pk) - } - -} - // works with java 7, 8, 11 & bouncycastle provider // https://connect2id.com/products/nimbus-jose-jwt/jca-algorithm-support#alg-support-table class ES256KSigner(privateKey: PrivateKey) extends Signer { diff --git a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/JWTVerification.scala b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/JWTVerification.scala index c40f8f3cdd..fbebe05907 100644 --- a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/JWTVerification.scala +++ b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/JWTVerification.scala @@ -22,7 +22,7 @@ object JWTVerification { // https://github.com/decentralized-identity/did-jwt/blob/8b3655097a1382934cabdf774d580e6731a636b1/src/JWT.ts#L146 val SUPPORT_PUBLIC_KEY_TYPES: Map[String, Set[String]] = Map( "ES256K" -> Set("EcdsaSecp256k1VerificationKey2019", "JsonWebKey2020"), - "ES256" -> Set("ES256") // TODO: Only use valid type (added just for compatibility in the Demo code) + // Add support for other key types here ) def validateAlgorithm(jwt: JWT): Validation[String, Unit] = { diff --git a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/VerifiableCredentialPayload.scala b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/VerifiableCredentialPayload.scala index f99dc7a492..445b707dd7 100644 --- a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/VerifiableCredentialPayload.scala +++ b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/VerifiableCredentialPayload.scala @@ -17,6 +17,8 @@ import java.security.PublicKey import java.time.temporal.TemporalAmount import java.time.{Clock, Instant, OffsetDateTime, ZoneId} import scala.util.Try +import com.nimbusds.jwt.SignedJWT +import scala.util.Failure opaque type DID = String object DID { @@ -711,9 +713,15 @@ object JwtCredential { def encodeJwt(payload: JwtCredentialPayload, issuer: Issuer): JWT = issuer.signer.encode(payload.asJson) def decodeJwt(jwt: JWT, publicKey: PublicKey): Try[JwtCredentialPayload] = { - JwtCirce - .decodeRaw(jwt.value, publicKey, options = JwtOptions(expiration = false, notBefore = false)) - .flatMap(decode[JwtCredentialPayload](_).toTry) + val signedJWT = SignedJWT.parse(jwt.value) + val verifier = JWTVerification.toECDSAVerifier(publicKey) + + val isSignatureValid = signedJWT.verify(verifier) + + if isSignatureValid then + val claimsSet = signedJWT.getJWTClaimsSet.toString + decode[JwtCredentialPayload](claimsSet).toTry + else Failure(Exception(s"Invalid JWT signature for: ${JWT.value}")) } def decodeJwt(jwt: JWT): IO[String, JwtCredentialPayload] = { @@ -731,7 +739,9 @@ object JwtCredential { } def validateEncodedJwt(jwt: JWT, publicKey: PublicKey): Boolean = - JwtCirce.isValid(jwt.value, publicKey, JwtOptions(expiration = false, notBefore = false)) + val signedJWT = SignedJWT.parse(jwt.value) + val verifier = JWTVerification.toECDSAVerifier(publicKey) + signedJWT.verify(verifier) def validateEncodedJWT( jwt: JWT, diff --git a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/CredentialDemo.scala b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/CredentialDemo.scala deleted file mode 100644 index fd3c48733a..0000000000 --- a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/CredentialDemo.scala +++ /dev/null @@ -1,105 +0,0 @@ -package org.hyperledger.identus.pollux.vc.jwt.demos - -import io.circe.* -import io.circe.parser.decode -import io.circe.syntax.* -import org.hyperledger.identus.pollux.vc.jwt.* -import org.hyperledger.identus.pollux.vc.jwt.CredentialPayload.Implicits.* -import java.time.Instant - -@main def CredentialDemo(): Unit = - val w3cCredentialPayload = W3cCredentialPayload( - `@context` = Set("https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1"), - maybeId = Some("http://example.edu/credentials/3732"), - `type` = Set("VerifiableCredential", "UniversityDegreeCredential"), - issuer = DID("https://example.edu/issuers/565049"), - issuanceDate = Instant.parse("2010-01-01T00:00:00Z"), - maybeExpirationDate = Some(Instant.parse("2010-01-12T00:00:00Z")), - maybeCredentialSchema = Some( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) - ), - credentialSubject = Json.obj( - "userName" -> Json.fromString("Bob"), - "age" -> Json.fromInt(42), - "email" -> Json.fromString("email") - ), - maybeCredentialStatus = Some( - CredentialStatus( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "StatusList2021Entry", - statusPurpose = StatusPurpose.Revocation, - statusListIndex = 0, - statusListCredential = "https://example.com/credentials/status/3" - ) - ), - maybeRefreshService = Some( - RefreshService( - id = "https://example.edu/refresh/3732", - `type` = "ManualRefreshService2018" - ) - ), - maybeEvidence = Option.empty, - maybeTermsOfUse = Option.empty - ) - - println("") - println("==================") - println("W3C => W3C Json") - println("==================") - val w3cJson = w3cCredentialPayload.asJson.toString() - println(w3cJson) - - println("") - println("==================") - println("W3C Json => W3C") - println("==================") - val decodedW3CJson = decode[W3cCredentialPayload](w3cJson).toOption.get - println(decodedW3CJson) - - println("") - println("==================") - println("W3C => JWT") - println("==================") - val jwtCredentialPayload = w3cCredentialPayload.toJwtCredentialPayload - println(jwtCredentialPayload) - - println("") - println("==================") - println("JWT => JWT+AUD") - println("==================") - val jwtAudCredentialPayload = - jwtCredentialPayload.copy(aud = - Set("did:example:4a57546973436f6f6c4a4a57573", "did:example:s7dfsd86f5sd6fsdf6sfs6d5sdf") - ) - println(jwtAudCredentialPayload) - - println("") - println("==================") - println("JWT+AUD => JWT+AUD Json") - println("==================") - val jwtAudCredentialJson = jwtAudCredentialPayload.asJson.toString() - println(jwtAudCredentialJson) - - println("") - println("==================") - println("JWT+AUD Json => JWT+AUD ") - println("==================") - val decodedJwtAudCredentialPayload = decode[JwtCredentialPayload](jwtAudCredentialJson).toOption.get - println(decodedJwtAudCredentialPayload) - - println("") - println("==================") - println("JWT+AUD => W3C") - println("==================") - val convertedJwtAudToW3CCredential = decodedJwtAudCredentialPayload.toW3CCredentialPayload - println(convertedJwtAudToW3CCredential.asJson.toString()) - - println("") - println("==================") - println("W3C => JWT+AUD") - println("==================") - val convertedW3CToJwtAudCredential = convertedJwtAudToW3CCredential.toJwtCredentialPayload - println(convertedW3CToJwtAudCredential.asJson.toString()) diff --git a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtCredentialDIDDocumentValidationDemo.scala b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtCredentialDIDDocumentValidationDemo.scala deleted file mode 100644 index dc4d4a546e..0000000000 --- a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtCredentialDIDDocumentValidationDemo.scala +++ /dev/null @@ -1,203 +0,0 @@ -package org.hyperledger.identus.pollux.vc.jwt.demos - -import com.nimbusds.jose.jwk.* -import io.circe.* -import org.hyperledger.identus.pollux.vc.jwt.* -import org.hyperledger.identus.pollux.vc.jwt.schema.{PlaceholderSchemaValidator, SchemaResolver} -import pdi.jwt.JwtAlgorithm -import zio.* -import zio.Console.* -import java.security.* -import java.security.interfaces.{ECPrivateKey, ECPublicKey} -import java.time.Instant -import scala.collection.immutable.Set - -object JwtCredentialDIDDocumentValidationDemo extends ZIOAppDefault { - def run = - def createUser(did: DID) = { - val keyGen = KeyPairGenerator.getInstance("EC") - keyGen.initialize(Curve.P_256.toECParameterSpec) - val keyPair = keyGen.generateKeyPair() - val privateKey = keyPair.getPrivate - val publicKey = keyPair.getPublic - ( - Issuer( - did = did, - signer = ES256Signer(privateKey), - publicKey = publicKey - ), - new ECKey.Builder(Curve.P_256, publicKey.asInstanceOf[ECPublicKey]) - .privateKey(privateKey.asInstanceOf[ECPrivateKey]) - .build() - ) - } - - println("") - println("==================") - println("Create Issuer1") - println("==================") - val (issuer1, issuer1Jwk) = - createUser(DID("did:issuer1:MDP8AsFhHzhwUvGNuYkX7T")) - println(issuer1) - - println("") - println("==================") - println("Create Issuer2") - println("==================") - val (issuer2, issuer2Jwk) = - createUser(DID("did:issuer2:MDP8AsFhHzhwUvGNuYkX7T")) - println(issuer2) - - println("") - println("==================") - println("Create Issuer3") - println("==================") - val (issuer3, issuer3Jwk) = - createUser(DID("did:issuer3:MDP8AsFhHzhwUvGNuYkX7T")) - println(issuer3) - - println("") - println("==================") - println("Create JWT Credential") - println("==================") - val jwtCredentialPayload = - JwtCredentialPayload( - iss = "https://example.edu/issuers/565049", // ISSUER DID - maybeSub = Some("1"), // SUBJECT DID - vc = JwtVc( - `@context` = Set("https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1"), - `type` = Set("VerifiableCredential", "UniversityDegreeCredential"), - maybeCredentialSchema = Some( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) - ), - credentialSubject = Json.obj( - "id" -> Json.fromString("1"), - "userName" -> Json.fromString("Bob"), - "age" -> Json.fromInt(42), - "email" -> Json.fromString("email") - ), - maybeCredentialStatus = Some( - CredentialStatus( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "StatusList2021Entry", - statusPurpose = StatusPurpose.Revocation, - statusListIndex = 0, - statusListCredential = "https://example.com/credentials/status/3" - ) - ), - maybeRefreshService = Some( - RefreshService( - id = "https://example.edu/refresh/3732", - `type` = "ManualRefreshService2018" - ) - ), - maybeEvidence = Option.empty, - maybeTermsOfUse = Option.empty - ), - nbf = Instant.parse("2010-01-01T00:00:00Z"), // ISSUANCE DATE - aud = Set.empty, - maybeExp = Some(Instant.parse("2010-01-12T00:00:00Z")), // EXPIRATION DATE - maybeJti = Some("http://example.edu/credentials/3732") // CREDENTIAL ID - ) - - val schemaResolved = new SchemaResolver { - override def resolve(credentialSchema: CredentialSchema): IO[String, Json] = { - println("Resolving Schema") - val resolvedSchema = - """ - |{ - | "type": "object", - | "properties": { - | "userName": { - | "$ref": "#/$defs/user" - | }, - | "age": { - | "$ref": "#/$defs/age" - | }, - | "email": { - | "$ref": "#/$defs/email" - | } - | }, - | "required": ["userName", "age", "email"], - | "$defs": { - | "user": { - | "type": "string", - | "minLength": 3 - | }, - | "age": { - | "type": "number" - | }, - | "email": { - | "type": "string", - | "format": "email" - | } - | } - |} - |""".stripMargin - ZIO.succeed(io.circe.parser.parse(resolvedSchema).toOption.get) - } - } - - class DidResolverTest() extends DidResolver { - - override def resolve(didUrl: String): UIO[DIDResolutionResult] = { - val Issuer1Key = - VerificationMethod( - id = "Issuer1Key", - `type` = JwtAlgorithm.ES256.name, - controller = "", - publicKeyJwk = Some( - toJWKFormat(issuer1Jwk) - ) - ) - val issuer2Key = VerificationMethod( - id = "Issuer2Key", - `type` = JwtAlgorithm.ES256.name, - controller = "", - publicKeyJwk = Some( - toJWKFormat(issuer2Jwk) - ) - ) - val didDocument = DIDDocument( - id = "Test", - alsoKnowAs = Vector.empty, - controller = Vector.empty, - verificationMethod = Vector( - Issuer1Key, // <------ ISSUER PUBLIC-KEY 1 - issuer2Key // <------ ISSUER PUBLIC-KEY 2 - ), - service = Vector.empty - ) - ZIO.succeed( - DIDResolutionSucceeded( - didDocument, // <------ DID DOCUMENT - DIDDocumentMetadata() - ) - ) - } - } - - println("") - println("==================") - println("Encode JWT Credential") - println("==================") - val encodedJwt = JwtCredential.encodeJwt(jwtCredentialPayload, issuer = issuer2) - - println("") - println("==================") - println("Validate JWT Credential Using DID Document of the Issuer of the Credential") - println("==================") - val validator = - JwtCredential.validateSchemaAndSignature(encodedJwt)(DidResolverTest())(schemaResolved)( - PlaceholderSchemaValidator.fromSchema - ) - - for { - _ <- printLine("DEMO TIME! ") - result <- validator - _ <- printLine(s"IS VALID?: $result") - } yield () -} diff --git a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtCredentialEncodingDemo.scala b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtCredentialEncodingDemo.scala deleted file mode 100644 index bd3347ae8a..0000000000 --- a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtCredentialEncodingDemo.scala +++ /dev/null @@ -1,108 +0,0 @@ -package org.hyperledger.identus.pollux.vc.jwt.demos - -import io.circe.* -import io.circe.syntax.* -import org.hyperledger.identus.pollux.vc.jwt.* -import org.hyperledger.identus.pollux.vc.jwt.CredentialPayload.Implicits.* -import java.security.* -import java.security.spec.* -import java.time.Instant - -@main def JwtCredentialEncodingDemo(): Unit = - - println("") - println("==================") - println("Create Issuer") - println("==================") - val keyGen = KeyPairGenerator.getInstance("EC") - val ecSpec = ECGenParameterSpec("secp256r1") - keyGen.initialize(ecSpec, SecureRandom()) - val keyPair = keyGen.generateKeyPair() - val privateKey = keyPair.getPrivate - val publicKey = keyPair.getPublic - val issuer = - Issuer( - did = DID("did:issuer:MDP8AsFhHzhwUvGNuYkX7T"), - signer = ES256Signer(privateKey), - publicKey = publicKey - ) - println(issuer) - - println("") - println("==================") - println("Create W3C") - println("==================") - val w3cCredentialPayload = - W3cCredentialPayload( - `@context` = Set("https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1"), - maybeId = Some("http://example.edu/credentials/3732"), - `type` = Set("VerifiableCredential", "UniversityDegreeCredential"), - issuer = DID("https://example.edu/issuers/565049"), - issuanceDate = Instant.parse("2010-01-01T00:00:00Z"), - maybeExpirationDate = Some(Instant.parse("2010-01-12T00:00:00Z")), - maybeCredentialSchema = Some( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) - ), - credentialSubject = Json.obj( - "userName" -> Json.fromString("Bob"), - "age" -> Json.fromInt(42), - "email" -> Json.fromString("email") - ), - maybeCredentialStatus = Some( - CredentialStatus( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "StatusList2021Entry", - statusPurpose = StatusPurpose.Revocation, - statusListIndex = 0, - statusListCredential = "https://example.com/credentials/status/3" - ) - ), - maybeRefreshService = Some( - RefreshService( - id = "https://example.edu/refresh/3732", - `type` = "ManualRefreshService2018" - ) - ), - maybeEvidence = Option.empty, - maybeTermsOfUse = Option.empty - ) - println(w3cCredentialPayload.asJson.toString()) - - println("") - println("==================") - println("W3C => Encoded JWT") - println("==================") - val encodedJWT = W3CCredential.toEncodedJwt(w3cCredentialPayload, issuer) - println(encodedJWT) - - println("") - println("==================") - println("Validate: Encoded JWT") - println("==================") - val valid = JwtCredential.validateEncodedJwt(encodedJWT, issuer.publicKey) - println(s"Is Valid? $valid") - - println("") - println("==================") - println("Encoded JWT -> Decoded JWT") - println("==================") - val decodedJwtCredential = JwtCredential.decodeJwt(encodedJWT, issuer.publicKey) - val decodedJwtCredentialAsJson = decodedJwtCredential.toOption.get.asJson.toString() - println(decodedJwtCredentialAsJson) - - println("") - println("==================") - println("W3C -> JWT") - println("==================") - val jwtCredentialPayload = w3cCredentialPayload.toJwtCredentialPayload - val jwtCredentialPayloadAsJson = jwtCredentialPayload.asJson.toString() - println(jwtCredentialPayloadAsJson) - - println("") - println("==================") - println("JWT Json = Decoded JWT (W3C -> Decoded JWT -> Encoded JWT -> Decoded JWT )") - println("==================") - println(s"Are equal? ${jwtCredentialPayloadAsJson == decodedJwtCredentialAsJson}") diff --git a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtCredentialTemporalVerificationDemo.scala b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtCredentialTemporalVerificationDemo.scala deleted file mode 100644 index 07ed493702..0000000000 --- a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtCredentialTemporalVerificationDemo.scala +++ /dev/null @@ -1,151 +0,0 @@ -package org.hyperledger.identus.pollux.vc.jwt.demos - -import io.circe.* -import io.circe.syntax.* -import org.hyperledger.identus.pollux.vc.jwt.* -import org.hyperledger.identus.pollux.vc.jwt.CredentialPayload.Implicits.* - -import java.security.* -import java.security.spec.* -import java.time.* - -@main def JwtCredentialTemporalVerificationDemo(): Unit = - - println("") - println("==================") - println("Create Issuer") - println("==================") - val keyGen = KeyPairGenerator.getInstance("EC") - val ecSpec = ECGenParameterSpec("secp256r1") - keyGen.initialize(ecSpec, SecureRandom()) - val keyPair = keyGen.generateKeyPair() - val privateKey = keyPair.getPrivate - val publicKey = keyPair.getPublic - val issuer = - Issuer( - did = DID("did:issuer:MDP8AsFhHzhwUvGNuYkX7T"), - signer = ES256Signer(privateKey), - publicKey = publicKey - ) - println(issuer) - - println("") - println("==================") - println("Create JWT Credential") - println("==================") - val nbf = Instant.parse("2010-01-01T00:00:00Z") // ISSUANCE DATE - val exp = Instant.parse("2010-01-12T00:00:00Z") // EXPIRATION DATE - val jwtCredentialPayload = - JwtCredentialPayload( - iss = "https://example.edu/issuers/565049", // ISSUER DID - maybeSub = Some("1"), // SUBJECT DID - vc = JwtVc( - `@context` = Set("https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1"), - `type` = Set("VerifiableCredential", "UniversityDegreeCredential"), - maybeCredentialSchema = Some( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) - ), - credentialSubject = Json.obj( - "id" -> Json.fromString("1"), - "userName" -> Json.fromString("Bob"), - "age" -> Json.fromInt(42), - "email" -> Json.fromString("email") - ), - maybeCredentialStatus = Some( - CredentialStatus( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "StatusList2021Entry", - statusPurpose = StatusPurpose.Revocation, - statusListIndex = 0, - statusListCredential = "https://example.com/credentials/status/3" - ) - ), - maybeRefreshService = Some( - RefreshService( - id = "https://example.edu/refresh/3732", - `type` = "ManualRefreshService2018" - ) - ), - maybeEvidence = Option.empty, - maybeTermsOfUse = Option.empty - ), - nbf = nbf, // ISSUANCE DATE - aud = Set.empty, - maybeExp = Some(exp), // EXPIRATION DATE - maybeJti = Some("http://example.edu/credentials/3732") // CREDENTIAL ID - ) - println(jwtCredentialPayload.asJson.toString()) - - println("") - println("==================") - println("Encoded JWT") - println("==================") - val encodedJWT = JwtCredential.encodeJwt(payload = jwtCredentialPayload, issuer = issuer) - println(encodedJWT) - - println("") - println("==================") - println("Validate JWT between ISSUANCE DATE and EXPIRATION DATE") - println("==================") - val clockWithCurrentTime = Clock.fixed(nbf.plus(Duration.ofDays(1)), ZoneId.systemDefault) - val validAtCurrentTime = - JwtCredential.verifyDates(jwt = encodedJWT, leeway = Duration.ZERO)(clock = clockWithCurrentTime) - println(s"Is Valid at current time? $validAtCurrentTime") - - println("") - println("==================") - println("Validate JWT on ISSUANCE DATE") - println("==================") - val clockWithFixedTimeAtNbf = Clock.fixed(nbf, ZoneId.systemDefault) - val validAtNbf = - JwtCredential.verifyDates(jwt = encodedJWT, leeway = Duration.ZERO)(clock = clockWithFixedTimeAtNbf) - println(s"Is Valid at ISSUANCE DATE? $validAtNbf") - - println("") - println("==================") - println("Validate JWT on EXPIRATION DATE") - println("==================") - val clockWithFixedTimeAtExp = Clock.fixed(exp, ZoneId.systemDefault) - val validAtExp = - JwtCredential.verifyDates(jwt = encodedJWT, leeway = Duration.ZERO)(clock = clockWithFixedTimeAtExp) - println(s"Is Valid at EXPIRATION DATE? $validAtExp") - - println("") - println("==================") - println("Validate JWT before ISSUANCE DATE") - println("==================") - val clockWithFixedTimeBeforeNbf = Clock.fixed(nbf.minus(Duration.ofDays(1)), ZoneId.systemDefault) - val validBeforeNbf = - JwtCredential.verifyDates(jwt = encodedJWT, leeway = Duration.ZERO)(clock = clockWithFixedTimeBeforeNbf) - println(s"Is Valid before ISSUANCE DATE? $validBeforeNbf") - - println("") - println("==================") - println("Validate JWT after EXPIRATION DATE") - println("==================") - val clockWithFixedTimeAfterExp = Clock.fixed(exp.plus(Duration.ofDays(1)), ZoneId.systemDefault) - val validAfterExp = - JwtCredential.verifyDates(jwt = encodedJWT, leeway = Duration.ZERO)(clock = clockWithFixedTimeAfterExp) - println(s"Is Valid after EXPIRATION DATE? $validAfterExp") - - println("") - println("==================") - println("Validate JWT before ISSUANCE DATE with 1 Day Leeway") - println("==================") - val leeway = Duration.ofDays(1) - val validBeforeNbfWithLeeway = - JwtCredential.verifyDates(jwt = encodedJWT, leeway = leeway)(clock = clockWithFixedTimeBeforeNbf) - println( - s"Is Valid before ISSUANCE DATE with 1 Day Leeway? $validBeforeNbfWithLeeway with leeway:$leeway" - ) - - println("") - println("==================") - println("Validate JWT after EXPIRATION DATE with 1 Day Leeway") - println("==================") - val validAfterExpWithLeeway = - JwtCredential.verifyDates(jwt = encodedJWT, leeway = leeway)(clock = clockWithFixedTimeAfterExp) - println(s"Is Valid after EXPIRATION DATE with 1 Day Leeway? $validAfterExpWithLeeway with leeway:$leeway") diff --git a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtPresentationCredentialDemo.scala b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtPresentationCredentialDemo.scala deleted file mode 100644 index f103d787e3..0000000000 --- a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtPresentationCredentialDemo.scala +++ /dev/null @@ -1,161 +0,0 @@ -package org.hyperledger.identus.pollux.vc.jwt.demos - -import io.circe.* -import io.circe.syntax.* -import org.hyperledger.identus.pollux.vc.jwt.* -import org.hyperledger.identus.pollux.vc.jwt.CredentialPayload.Implicits.* -import org.hyperledger.identus.pollux.vc.jwt.PresentationPayload.Implicits.* - -import java.security.* -import java.security.spec.* -import java.time.Instant - -@main def JwtPresentationWithJWTCredentialDemo(): Unit = - - def createUser(did: DID) = { - val keyGen = KeyPairGenerator.getInstance("EC") - val ecSpec = ECGenParameterSpec("secp256r1") - keyGen.initialize(ecSpec, SecureRandom()) - val keyPair = keyGen.generateKeyPair() - val privateKey = keyPair.getPrivate - val publicKey = keyPair.getPublic - Issuer( - did = did, - signer = ES256Signer(privateKey), - publicKey = publicKey - ) - } - - println("") - println("==================") - println("Create Issuer") - println("==================") - val issuer = - createUser(DID("did:issuer:MDP8AsFhHzhwUvGNuYkX7T")) - println(issuer) - - println("") - println("==================") - println("Create Holder") - println("==================") - val holder = - createUser(DID("did:holder:MDP8AsFhHzhwUvGNuYkX7T")) - println(holder) - - println("") - println("==================") - println("Create W3C Presentation") - println("==================") - val w3cCredentialPayload = - W3cCredentialPayload( - `@context` = Set("https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1"), - maybeId = Some("http://example.edu/credentials/3732"), - `type` = Set("VerifiableCredential", "UniversityDegreeCredential"), - issuer = DID("https://example.edu/issuers/565049"), - issuanceDate = Instant.parse("2010-01-01T00:00:00Z"), - maybeExpirationDate = Some(Instant.parse("2010-01-12T00:00:00Z")), - maybeCredentialSchema = Some( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) - ), - credentialSubject = Json.obj( - "userName" -> Json.fromString("Bob"), - "age" -> Json.fromInt(42), - "email" -> Json.fromString("email") - ), - maybeCredentialStatus = Some( - CredentialStatus( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "StatusList2021Entry", - statusPurpose = StatusPurpose.Revocation, - statusListIndex = 0, - statusListCredential = "https://example.com/credentials/status/3" - ) - ), - maybeRefreshService = Some( - RefreshService( - id = "https://example.edu/refresh/3732", - `type` = "ManualRefreshService2018" - ) - ), - maybeEvidence = Option.empty, - maybeTermsOfUse = Option.empty - ) - - val w3cIssuerSignedCredential = issuer.signer.encode(w3cCredentialPayload.asJson) - val w3cVerifiableCredentialPayload = - W3cVerifiableCredentialPayload( - payload = w3cCredentialPayload, - proof = JwtProof( - `type` = "JwtProof2020", - jwt = w3cIssuerSignedCredential - ) - ) - - val JWTIssuerSignedCredential = issuer.signer.encode(w3cCredentialPayload.toJwtCredentialPayload.asJson) - val jwtVerifiableCredentialPayload = JwtVerifiableCredentialPayload(JWTIssuerSignedCredential) - - val w3cPresentationPayload = - W3cPresentationPayload( - `@context` = - Vector("https://www.w3.org/2018/presentations/v1", "https://www.w3.org/2018/presentations/examples/v1"), - maybeId = Some("http://example.edu/presentations/3732"), - `type` = Vector("VerifiablePresentation", "UniversityDegreePresentation"), - verifiableCredential = Vector(w3cVerifiableCredentialPayload, jwtVerifiableCredentialPayload), - holder = "https://example.edu/holder/565049", - verifier = Vector("https://example.edu/issuers/565049"), - maybeIssuanceDate = Some(Instant.parse("2010-01-01T00:00:00Z")), - maybeExpirationDate = Some(Instant.parse("2010-01-12T00:00:00Z")) - ) - println(w3cPresentationPayload.asJson.toString()) - - println("") - println("==================") - println("W3C Presentation => Encoded JWT") - println("==================") - val encodedJWT = JwtPresentation.toEncodedJwt(w3cPresentationPayload, holder) - println(encodedJWT) - - println("") - println("==================") - println("Validate Encoded JWT") - println("==================") - val valid = JwtPresentation.validateEncodedJwt(encodedJWT, holder.publicKey) - println(s"Is Valid? $valid") - - println("") - println("==================") - println("Encoded JWT => Decoded JWT Presentation Json") - println("==================") - val decodedJwtPresentation = JwtPresentation.decodeJwt(encodedJWT, holder.publicKey).toOption.get - val decodedJwtPresentationAsJson = decodedJwtPresentation.asJson.toString() - println(decodedJwtPresentationAsJson) - - println("") - println("==================") - println("Validates Signature Of Credentials") - println("==================") - decodedJwtPresentation.vp.verifiableCredential.foreach { - case (w3cVerifiableCredentialPayload: W3cVerifiableCredentialPayload) => - println(s"w3cVerifiableCredentialPayload Is Valid? ${JwtPresentation - .validateEncodedJwt(w3cVerifiableCredentialPayload.proof.jwt, issuer.publicKey)}") - case (jwtVerifiableCredentialPayload: JwtVerifiableCredentialPayload) => - println(s"jwtVerifiableCredentialPayload Is Valid? ${JwtPresentation - .validateEncodedJwt(jwtVerifiableCredentialPayload.jwt, issuer.publicKey)}") - } - - println("") - println("==================") - println("W3C Presentation => JWT Presentation Json") - println("==================") - val jwtPresentationPayload = w3cPresentationPayload.toJwtPresentationPayload - val jwtPresentationPayloadAsJson = jwtPresentationPayload.asJson.toString() - println(jwtPresentationPayloadAsJson) - - println("") - println("==================") - println("JWT Presentation Json = Decoded JWT Presentation Json") - println("==================") - println(s"Are equal? ${jwtPresentationPayloadAsJson == decodedJwtPresentationAsJson}") diff --git a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtPresentationTemporalVerificationDemo.scala b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtPresentationTemporalVerificationDemo.scala deleted file mode 100644 index 8eab14abec..0000000000 --- a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtPresentationTemporalVerificationDemo.scala +++ /dev/null @@ -1,279 +0,0 @@ -package org.hyperledger.identus.pollux.vc.jwt.demos - -import io.circe.* -import io.circe.syntax.* -import org.hyperledger.identus.pollux.vc.jwt.* -import org.hyperledger.identus.pollux.vc.jwt.CredentialPayload.Implicits.* -import org.hyperledger.identus.pollux.vc.jwt.PresentationPayload.Implicits.* - -import java.security.* -import java.security.spec.* -import java.time.* -import scala.collection.immutable.Set - -@main def JwtPresentationTemporalVerificationDemo(): Unit = - def createUser(did: DID) = { - val keyGen = KeyPairGenerator.getInstance("EC") - val ecSpec = ECGenParameterSpec("secp256r1") - keyGen.initialize(ecSpec, SecureRandom()) - val keyPair = keyGen.generateKeyPair() - val privateKey = keyPair.getPrivate - val publicKey = keyPair.getPublic - Issuer( - did = did, - signer = ES256Signer(privateKey), - publicKey = publicKey - ) - } - - println("") - println("==================") - println("Create Issuer") - println("==================") - val issuer = - createUser(DID("did:issuer:MDP8AsFhHzhwUvGNuYkX7T")) - println(issuer) - - println("") - println("==================") - println("Create Holder") - println("==================") - val holder = - createUser(DID("did:holder:MDP8AsFhHzhwUvGNuYkX7T")) - println(holder) - - println("") - println("==================") - println("Create W3C Presentation") - println("==================") - val w3cIssuanceDate = Instant.parse("2010-01-01T00:00:00Z") // ISSUANCE DATE - val w3cExpirationDate = Instant.parse("2010-01-12T00:00:00Z") // EXPIRATION DATE - val w3cCredentialPayload = - W3cCredentialPayload( - `@context` = Set("https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1"), - maybeId = Some("http://example.edu/credentials/3732"), - `type` = Set("VerifiableCredential", "UniversityDegreeCredential"), - issuer = DID("https://example.edu/issuers/565049"), - issuanceDate = w3cIssuanceDate, - maybeExpirationDate = Some(w3cExpirationDate), - maybeCredentialSchema = Some( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) - ), - credentialSubject = Json.obj( - "userName" -> Json.fromString("Bob"), - "age" -> Json.fromInt(42), - "email" -> Json.fromString("email") - ), - maybeCredentialStatus = Some( - CredentialStatus( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "StatusList2021Entry", - statusPurpose = StatusPurpose.Revocation, - statusListIndex = 0, - statusListCredential = "https://example.com/credentials/status/3" - ) - ), - maybeRefreshService = Some( - RefreshService( - id = "https://example.edu/refresh/3732", - `type` = "ManualRefreshService2018" - ) - ), - maybeEvidence = Option.empty, - maybeTermsOfUse = Option.empty - ) - - val w3cIssuerSignedCredential = issuer.signer.encode(w3cCredentialPayload.asJson) - val w3cVerifiableCredentialPayload = - W3cVerifiableCredentialPayload( - payload = w3cCredentialPayload, - proof = JwtProof( - `type` = "JwtProof2020", - jwt = w3cIssuerSignedCredential - ) - ) - - val jwtCredentialNbf = Instant.parse("2010-01-01T00:00:00Z") // ISSUANCE DATE - val jwtCredentialExp = Instant.parse("2010-01-12T00:00:00Z") // EXPIRATION DATE - val jwtCredentialPayload = - JwtCredentialPayload( - iss = "https://example.edu/issuers/565049", // ISSUER DID - maybeSub = Some("1"), // SUBJECT DID - vc = JwtVc( - `@context` = Set("https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1"), - `type` = Set("VerifiableCredential", "UniversityDegreeCredential"), - maybeCredentialSchema = Some( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) - ), - credentialSubject = Json.obj( - "id" -> Json.fromString("1"), - "userName" -> Json.fromString("Bob"), - "age" -> Json.fromInt(42), - "email" -> Json.fromString("email") - ), - maybeCredentialStatus = Some( - CredentialStatus( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "StatusList2021Entry", - statusPurpose = StatusPurpose.Revocation, - statusListIndex = 0, - statusListCredential = "https://example.com/credentials/status/3" - ) - ), - maybeRefreshService = Some( - RefreshService( - id = "https://example.edu/refresh/3732", - `type` = "ManualRefreshService2018" - ) - ), - maybeEvidence = Option.empty, - maybeTermsOfUse = Option.empty - ), - nbf = jwtCredentialNbf, // ISSUANCE DATE - aud = Set.empty, - maybeExp = Some(jwtCredentialExp), // EXPIRATION DATE - maybeJti = Some("http://example.edu/credentials/3732") // CREDENTIAL ID - ) - - val JWTIssuerSignedCredential = issuer.signer.encode(jwtCredentialPayload.asJson) - val jwtVerifiableCredentialPayload = JwtVerifiableCredentialPayload(JWTIssuerSignedCredential) - - val jwtPresentationNbf = Instant.parse("2010-01-01T00:00:00Z") // ISSUANCE DATE - val jwtPresentationExp = Instant.parse("2010-01-12T00:00:00Z") // EXPIRATION DATE - - def presentationPayload( - maybeJwtPresentationNbf: Option[Instant], - maybeJwtPresentationExp: Option[Instant] - ): JwtPresentationPayload = { - JwtPresentationPayload( - iss = "https://example.edu/holder/565049", - maybeJti = Some("http://example.edu/presentations/3732"), - vp = JwtVp( - `@context` = - Vector("https://www.w3.org/2018/presentations/v1", "https://www.w3.org/2018/presentations/examples/v1"), - `type` = Vector("VerifiablePresentation", "UniversityDegreePresentation"), - verifiableCredential = Vector(w3cVerifiableCredentialPayload, jwtVerifiableCredentialPayload) - ), - aud = Vector("https://example.edu/issuers/565049"), - maybeNbf = maybeJwtPresentationNbf, - maybeExp = maybeJwtPresentationExp, - maybeNonce = None - ) - } - - val jwtPresentationPayload = presentationPayload(Some(jwtPresentationNbf), Some(jwtPresentationExp)) - println(jwtPresentationPayload.asJson.toString()) - - println("") - println("==================") - println("Encoded JWT") - println("==================") - val encodedJWTPresentation = JwtPresentation.encodeJwt(payload = jwtPresentationPayload, issuer = issuer) - println(encodedJWTPresentation) - - println("") - println("==================") - println("Validate JWT between ISSUANCE DATE and EXPIRATION DATE") - println("==================") - val clockWithCurrentTime = Clock.fixed(jwtPresentationNbf.plus(Duration.ofDays(1)), ZoneId.systemDefault) - val validAtCurrentTime = - JwtPresentation.verifyDates(jwt = encodedJWTPresentation, leeway = Duration.ZERO)(clock = clockWithCurrentTime) - println(s"Is Valid at current time? $validAtCurrentTime") - - println("") - println("==================") - println("Validate JWT on ISSUANCE DATE") - println("==================") - val clockWithFixedTimeAtNbf = Clock.fixed(jwtPresentationNbf, ZoneId.systemDefault) - val validAtNbf = - JwtPresentation.verifyDates(jwt = encodedJWTPresentation, leeway = Duration.ZERO)(clock = clockWithFixedTimeAtNbf) - println(s"Is Valid at ISSUANCE DATE? $validAtNbf") - - println("") - println("==================") - println("Validate JWT on EXPIRATION DATE") - println("==================") - val clockWithFixedTimeAtExp = Clock.fixed(jwtPresentationExp, ZoneId.systemDefault) - val validAtExp = - JwtPresentation.verifyDates(jwt = encodedJWTPresentation, leeway = Duration.ZERO)(clock = clockWithFixedTimeAtExp) - println(s"Is Valid at EXPIRATION DATE? $validAtExp") - - println("") - println("==================") - println("Validate JWT before ISSUANCE DATE") - println("==================") - val clockWithFixedTimeBeforeNbf = Clock.fixed(jwtPresentationNbf.minus(Duration.ofDays(1)), ZoneId.systemDefault) - val validBeforeNbf = - JwtPresentation.verifyDates(jwt = encodedJWTPresentation, leeway = Duration.ZERO)(clock = - clockWithFixedTimeBeforeNbf - ) - println(s"Is Valid before ISSUANCE DATE? $validBeforeNbf") - - println("") - println("==================") - println("Validate JWT after EXPIRATION DATE") - println("==================") - val clockWithFixedTimeAfterExp = Clock.fixed(jwtPresentationExp.plus(Duration.ofDays(1)), ZoneId.systemDefault) - val validAfterExp = - JwtPresentation.verifyDates(jwt = encodedJWTPresentation, leeway = Duration.ZERO)(clock = - clockWithFixedTimeAfterExp - ) - println(s"Is Valid after EXPIRATION DATE? $validAfterExp") - - println("") - println("==================") - println("Validate JWT before ISSUANCE DATE with 1 Day Leeway") - println("==================") - val leeway = Duration.ofDays(1) - val validBeforeNbfWithLeeway = - JwtPresentation.verifyDates(jwt = encodedJWTPresentation, leeway = leeway)(clock = clockWithFixedTimeBeforeNbf) - println( - s"Is Valid before ISSUANCE DATE with 1 Day Leeway? $validBeforeNbfWithLeeway with leeway:$leeway" - ) - - println("") - println("==================") - println("Validate JWT after EXPIRATION DATE with 1 Day Leeway") - println("==================") - val validAfterExpWithLeeway = - JwtPresentation.verifyDates(jwt = encodedJWTPresentation, leeway = leeway)(clock = clockWithFixedTimeAfterExp) - println(s"Is Valid after EXPIRATION DATE with 1 Day Leeway? $validAfterExpWithLeeway with leeway:$leeway") - - println("") - println("==================") - println("Validate JWT No ISSUANCE DATE") - println("==================") - val encodedJWTPresentationNoNB = - JwtPresentation.encodeJwt(payload = presentationPayload(None, Some(jwtPresentationExp)), issuer = issuer) - - val noNbfValidBeforeExpiration = - JwtPresentation.verifyDates(jwt = encodedJWTPresentationNoNB, leeway = Duration.ZERO)(clock = clockWithCurrentTime) - println(s"Is Valid before EXPIRATION DATE: $noNbfValidBeforeExpiration") - - println("") - println("==================") - println("Validated JWT No EXPIRATION DATE") - println("==================") - val encodedJWTPresentationNoEXP = - JwtPresentation.encodeJwt(payload = presentationPayload(Some(jwtPresentationNbf), None), issuer = issuer) - val noExpValidAfterNbf = - JwtPresentation.verifyDates(jwt = encodedJWTPresentationNoEXP, leeway = Duration.ZERO)(clock = clockWithCurrentTime) - println(s"Is Valid after ISSUANCE DATE: $noExpValidAfterNbf") - - println("") - println("==================") - println("Validate JWT No EXPIRATION & No ISSUANCE DATE") - println("==================") - val encodedJWTPresentationNoEXPNoNbf: JWT = - JwtPresentation.encodeJwt(payload = presentationPayload(None, None), issuer = issuer) - val noEXPAndNbfAlwaysValid = - JwtPresentation.verifyDates(jwt = encodedJWTPresentationNoEXPNoNbf, leeway = Duration.ZERO)(clock = - clockWithCurrentTime - ) - println(s"Is Always Valid With non EXPIRATION DATE & No ISSUANCE DATE: $noEXPAndNbfAlwaysValid") diff --git a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtPresentationVerificationDemo.scala b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtPresentationVerificationDemo.scala deleted file mode 100644 index 2139cb95bd..0000000000 --- a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/JwtPresentationVerificationDemo.scala +++ /dev/null @@ -1,275 +0,0 @@ -package org.hyperledger.identus.pollux.vc.jwt.demos - -import com.nimbusds.jose.jwk.{Curve, ECKey} -import io.circe.* -import io.circe.syntax.* -import org.hyperledger.identus.pollux.vc.jwt.* -import org.hyperledger.identus.pollux.vc.jwt.CredentialPayload.Implicits.* -import org.hyperledger.identus.pollux.vc.jwt.PresentationPayload.Implicits.* -import pdi.jwt.JwtAlgorithm -import zio.Console.printLine -import zio.{UIO, ZIO, ZIOAppDefault} - -import java.security.* -import java.security.interfaces.{ECPrivateKey, ECPublicKey} -import java.time.* -import scala.collection.immutable.Set - -case class IssuerWithKey(issuer: Issuer, key: ECKey) -object JwtPresentationVerificationDemo extends ZIOAppDefault { - def run = - def createUser(did: DID): IssuerWithKey = { - val keyGen = KeyPairGenerator.getInstance("EC") - keyGen.initialize(Curve.P_256.toECParameterSpec) - val keyPair = keyGen.generateKeyPair() - val privateKey = keyPair.getPrivate - val publicKey = keyPair.getPublic - IssuerWithKey( - Issuer( - did = did, - signer = ES256Signer(privateKey), - publicKey = publicKey - ), - new ECKey.Builder(Curve.P_256, publicKey.asInstanceOf[ECPublicKey]) - .privateKey(privateKey.asInstanceOf[ECPrivateKey]) - .build() - ) - } - - println("") - println("==================") - println("Create holder1") - println("==================") - val holder1 = createUser(DID("did:holder1:MDP8AsFhHzhwUvGNuYkX7T")) - println(holder1) - - println("") - println("==================") - println("Create holder2") - println("==================") - val holder2 = createUser(DID("did:holder2:MDP8AsFhHzhwUvGNuYkX7T")) - println(holder2) - - println("") - println("==================") - println("Create holder3") - println("==================") - val holder3 = createUser(DID("did:holder3:MDP8AsFhHzhwUvGNuYkX7T")) - println(holder3) - - println("") - println("==================") - println("Create issuer1") - println("==================") - val issuer1 = createUser(DID("did:issuer1:MDP8AsFhHzhwUvGNuYkX7T")) - println(issuer1) - - println("") - println("==================") - println("Create issuer1") - println("==================") - val issuer2 = createUser(DID("did:issuer2:MDP8AsFhHzhwUvGNuYkX7T")) - println(issuer2) - - println("") - println("==================") - println("Create W3C Presentation") - println("==================") - val w3cIssuanceDate = Instant.parse("2010-01-01T00:00:00Z") // ISSUANCE DATE - val w3cExpirationDate = Instant.parse("2010-01-12T00:00:00Z") // EXPIRATION DATE - val w3cCredentialPayload = - W3cCredentialPayload( - `@context` = Set("https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1"), - maybeId = Some("http://example.edu/credentials/3732"), - `type` = Set("VerifiableCredential", "UniversityDegreeCredential"), - issuer = issuer1.issuer.did, - issuanceDate = w3cIssuanceDate, - maybeExpirationDate = Some(w3cExpirationDate), - maybeCredentialSchema = Some( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) - ), - credentialSubject = Json.obj( - "userName" -> Json.fromString("Bob"), - "age" -> Json.fromInt(42), - "email" -> Json.fromString("email") - ), - maybeCredentialStatus = Some( - CredentialStatus( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "StatusList2021Entry", - statusPurpose = StatusPurpose.Revocation, - statusListIndex = 0, - statusListCredential = "https://example.com/credentials/status/3" - ) - ), - maybeRefreshService = Some( - RefreshService( - id = "https://example.edu/refresh/3732", - `type` = "ManualRefreshService2018" - ) - ), - maybeEvidence = Option.empty, - maybeTermsOfUse = Option.empty - ) - - val w3cIssuerSignedCredential = issuer1.issuer.signer.encode(w3cCredentialPayload.asJson) - val w3cVerifiableCredentialPayload = - W3cVerifiableCredentialPayload( - payload = w3cCredentialPayload, - proof = JwtProof( - `type` = "JwtProof2020", - jwt = w3cIssuerSignedCredential - ) - ) - - val jwtCredentialNbf = Instant.parse("2010-01-01T00:00:00Z") // ISSUANCE DATE - val jwtCredentialExp = Instant.parse("2010-01-12T00:00:00Z") // EXPIRATION DATE - val jwtCredentialPayload = - JwtCredentialPayload( - iss = issuer2.issuer.did.value, // ISSUER DID - maybeSub = Some("1"), // SUBJECT DID - vc = JwtVc( - `@context` = Set("https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1"), - `type` = Set("VerifiableCredential", "UniversityDegreeCredential"), - maybeCredentialSchema = Some( - CredentialSchema( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "JsonSchemaValidator2018" - ) - ), - credentialSubject = Json.obj( - "id" -> Json.fromString("1"), - "userName" -> Json.fromString("Bob"), - "age" -> Json.fromInt(42), - "email" -> Json.fromString("email") - ), - maybeCredentialStatus = Some( - CredentialStatus( - id = "did:work:MDP8AsFhHzhwUvGNuYkX7T;id=06e126d1-fa44-4882-a243-1e326fbe21db;version=1.0", - `type` = "StatusList2021Entry", - statusPurpose = StatusPurpose.Revocation, - statusListIndex = 0, - statusListCredential = "https://example.com/credentials/status/3" - ) - ), - maybeRefreshService = Some( - RefreshService( - id = "https://example.edu/refresh/3732", - `type` = "ManualRefreshService2018" - ) - ), - maybeEvidence = Option.empty, - maybeTermsOfUse = Option.empty - ), - nbf = jwtCredentialNbf, // ISSUANCE DATE - aud = Set.empty, - maybeExp = Some(jwtCredentialExp), // EXPIRATION DATE - maybeJti = Some("http://example.edu/credentials/3732") // CREDENTIAL ID - ) - - val jwtIssuerSignedCredential = issuer2.issuer.signer.encode(jwtCredentialPayload.asJson) - val jwtVerifiableCredentialPayload = JwtVerifiableCredentialPayload(jwtIssuerSignedCredential) - - val jwtPresentationNbf = Instant.parse("2010-01-01T00:00:00Z") // ISSUANCE DATE - val jwtPresentationExp = Instant.parse("2010-01-12T00:00:00Z") // EXPIRATION DATE - - def presentationPayload( - maybeJwtPresentationNbf: Option[Instant], - maybeJwtPresentationExp: Option[Instant] - ): JwtPresentationPayload = { - JwtPresentationPayload( - iss = holder1.issuer.did.value, - maybeJti = Some("http://example.edu/presentations/3732"), - vp = JwtVp( - `@context` = - Vector("https://www.w3.org/2018/presentations/v1", "https://www.w3.org/2018/presentations/examples/v1"), - `type` = Vector("VerifiablePresentation", "UniversityDegreePresentation"), - verifiableCredential = Vector(w3cVerifiableCredentialPayload, jwtVerifiableCredentialPayload) - ), - aud = Vector("https://example.edu/issuers/565049"), - maybeNbf = maybeJwtPresentationNbf, - maybeExp = maybeJwtPresentationExp, - maybeNonce = None - ) - } - - val jwtPresentationPayload = presentationPayload(Some(jwtPresentationNbf), Some(jwtPresentationExp)) - println(jwtPresentationPayload.asJson.toString()) - - class DidResolverTest() extends DidResolver { - - private val resolverLookup: Map[String, DIDDocument] = Seq(holder1, holder2, holder3, issuer1, issuer2).map { - issuerWithKey => - val did = issuerWithKey.issuer.did.value - val verificationMethod = - VerificationMethod( - id = did, - `type` = JwtAlgorithm.ES256.name, - controller = "", - publicKeyJwk = Some( - toJWKFormat(issuerWithKey.key) - ) - ) - did -> DIDDocument( - id = did, - alsoKnowAs = Vector.empty, - controller = Vector.empty, - verificationMethod = Vector(verificationMethod), - service = Vector.empty - ) - }.toMap - - override def resolve(didUrl: String): UIO[DIDResolutionResult] = - resolverLookup - .get(didUrl) - .fold( - ZIO.succeed(DIDResolutionFailed(NotFound(s"DIDDocument not found for $didUrl"))) - )((didDocument: DIDDocument) => { - ZIO.succeed( - DIDResolutionSucceeded( - didDocument, - DIDDocumentMetadata() - ) - ) - }) - - } - - println("") - println("==================") - println("Validate JWT Presentation Using DID Document of the issuer of the presentation") - println("==================") - val encodedJWTPresentation = JwtPresentation.encodeJwt(payload = jwtPresentationPayload, issuer = holder1.issuer) - val encodedW3CPresentation = - JwtPresentation.toEncodeW3C(payload = jwtPresentationPayload.toW3CPresentationPayload, issuer = holder1.issuer) - val clock = Clock.system(ZoneId.systemDefault) - for { - _ <- printLine("DEMO TIME! ") - w3cSignatureValidationResult <- JwtPresentation.validateEncodedW3C(encodedW3CPresentation.proof.jwt, None)( - DidResolverTest() - ) - jwtSignatureValidationResult <- JwtPresentation.validateEncodedJWT(encodedJWTPresentation, None)( - DidResolverTest() - ) - enclosedCredentialsValidationResult <- - JwtPresentation.verify( - encodedJWTPresentation, - JwtPresentation.PresentationVerificationOptions( - verifySignature = true, - verifyDates = true, - verifyHoldersBinding = true, - leeway = Duration.ZERO, - Some(CredentialVerification.CredentialVerificationOptions(verifySignature = true, verifyDates = true)) - ) - )( - DidResolverTest(), - (_: String) => ZIO.succeed("") - )(clock) - _ <- printLine(s"W3C IS VALID?: $w3cSignatureValidationResult") - _ <- printLine(s"JWT IS VALID?: $jwtSignatureValidationResult") - _ <- printLine(s"Enclosed Credentials are VALID?: $enclosedCredentialsValidationResult") - } yield () -} diff --git a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/SchemaDemo.scala b/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/SchemaDemo.scala deleted file mode 100644 index 77bea1dd20..0000000000 --- a/pollux/vc-jwt/src/main/scala/io/iohk/atala/pollux/vc/jwt/demos/SchemaDemo.scala +++ /dev/null @@ -1,83 +0,0 @@ -package org.hyperledger.identus.pollux.vc.jwt.demos - -import io.circe.* -import net.reactivecore.cjs.{DocumentValidator, Loader} - -@main def schemaDemo(): Unit = - val schemaCode = - """ - |{ - | "type": "object", - | "properties": { - | "userName": { - | "$ref": "#/$defs/user" - | }, - | "age": { - | "$ref": "#/$defs/age" - | }, - | "email": { - | "$ref": "#/$defs/email" - | } - | }, - | "required": ["userName", "age", "email"], - | "$defs": { - | "user": { - | "type": "string", - | "minLength": 3 - | }, - | "age": { - | "type": "number" - | }, - | "email": { - | "type": "string", - | "format": "email" - | } - | } - |} - |""".stripMargin - - val validator = Loader.empty.fromJson(io.circe.parser.parse(schemaCode).toOption.get) - - def test(s: Json): Unit = { - validator match { - case Right(v) => - val result = v.validate(s) - println(s"Result of $s: $result") - case Left(e) => - println(s"Validation failed with error: $e") - } - } - - test(Json.fromString("wrongType")) - test( - Json.obj( - "userName" -> Json.fromString("Bob"), - "age" -> Json.fromInt(42) - ) - ) - - // Missing UserName - test( - Json.obj( - "age" -> Json.fromInt(42), - "email" -> Json.fromString("email@email.com") - ) - ) - - // Age has Wrong type - test( - Json.obj( - "userName" -> Json.fromString("Bob"), - "age" -> Json.fromBoolean(false), - "email" -> Json.fromString("email@email.com") - ) - ) - - // Success - test( - Json.obj( - "userName" -> Json.fromString("Bob"), - "age" -> Json.fromInt(42), - "email" -> Json.fromString("email") - ) - ) diff --git a/pollux/vc-jwt/src/test/scala/io/iohk/atala/pollux/vc/jwt/revocation/VCStatusList2021Spec.scala b/pollux/vc-jwt/src/test/scala/io/iohk/atala/pollux/vc/jwt/revocation/VCStatusList2021Spec.scala index db69cc8952..a6f4be663f 100644 --- a/pollux/vc-jwt/src/test/scala/io/iohk/atala/pollux/vc/jwt/revocation/VCStatusList2021Spec.scala +++ b/pollux/vc-jwt/src/test/scala/io/iohk/atala/pollux/vc/jwt/revocation/VCStatusList2021Spec.scala @@ -1,34 +1,30 @@ package org.hyperledger.identus.pollux.vc.jwt.revocation -import org.hyperledger.identus.pollux.vc.jwt.{DID, ES256Signer, Issuer, JwtCredential} +import org.hyperledger.identus.pollux.vc.jwt.{DID, ES256KSigner, Issuer, JwtCredential} import zio.test.{Spec, ZIOSpecDefault, assertTrue} import zio.{UIO, ZIO} - -import java.security.spec.ECGenParameterSpec -import java.security.{KeyPairGenerator, SecureRandom} +import org.hyperledger.identus.shared.crypto.KmpSecp256k1KeyOps object VCStatusList2021Spec extends ZIOSpecDefault { private val VC_ID = "https://example.com/credentials/status/3" private def generateIssuer(): UIO[Issuer] = { - val keyGen = KeyPairGenerator.getInstance("EC") - val ecSpec = ECGenParameterSpec("secp256r1") - keyGen.initialize(ecSpec, SecureRandom()) - val keyPair = keyGen.generateKeyPair() - val privateKey = keyPair.getPrivate - val publicKey = keyPair.getPublic + + val keyPair = KmpSecp256k1KeyOps.generateKeyPair + val javaSKey = keyPair.privateKey.toJavaPrivateKey + val javaPKey = keyPair.publicKey.toJavaPublicKey + ZIO.succeed( Issuer( did = DID("did:issuer:MDP8AsFhHzhwUvGNuYkX7T"), - signer = ES256Signer(privateKey), - publicKey = publicKey + signer = ES256KSigner(javaSKey), + publicKey = javaPKey ) ) } override def spec = suite("VCStatusList2021")( - // TODO: add test to verify the proof is valid test("Should generate status list VC as JSON with embedded proof") { for { issuer <- generateIssuer() @@ -57,7 +53,6 @@ object VCStatusList2021Spec extends ZIOSpecDefault { bitString <- BitString.getInstance() statusList <- VCStatusList2021.build(VC_ID, s"$VC_ID#list", issuer, bitString) encodedJwtVC <- statusList.encoded - _ <- ZIO.logInfo(s"$encodedJwtVC") valid <- ZIO.succeed(JwtCredential.validateEncodedJwt(encodedJwtVC, issuer.publicKey)) } yield { assertTrue(valid)