Skip to content

Commit

Permalink
SD JWT moduel is done
Browse files Browse the repository at this point in the history
Signed-off-by: FabioPinheiro <fabiomgpinheiro@gmail.com>
  • Loading branch information
FabioPinheiro committed May 17, 2024
1 parent 0f6f569 commit 87f72bd
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters
import org.bouncycastle.crypto.util.PrivateKeyInfoFactory
import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters
import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory
import scala.util.Try
import scala.util.Failure
import scala.util.Success
import org.bouncycastle.cert.path.CertPathValidationResult

// TODO move to apollo
private[sdjwt] object Utils {
Expand Down Expand Up @@ -160,15 +164,15 @@ object SDJWT {
def createPresentation(
sdjwt: CredentialJson,
claimsToDisclose: String,
signAlg: String // FIXME
// signAlg: String // FIXME
): PresentationJson = {
val holder = SdjwtHolderWrapper(sdjwt.value, SdjwtSerializationFormat.JSON)
val presentation = holder.createPresentation(
claimsToDisclose,
null, // nonce
null, // aud
null, // holder_key
signAlg, // sign_alg
null, // signAlg, // sign_alg
)
PresentationJson(presentation)
}
Expand Down Expand Up @@ -201,16 +205,34 @@ object SDJWT {
PresentationJson(presentation)
}

def verifyPresentation(key: IssuerPublicKey, presentation: PresentationJson, claims: String) = {
val verifier = SdjwtVerifierWrapper(
presentation.value, // sd_jwt_presentation
key.pem, // public_key
null, // expected_aud
null, // expected_nonce
SdjwtSerializationFormat.JSON // serialization_format
)
val result: Boolean = verifier.verify(claims)
result
sealed trait ValidationResult
case object Valid extends ValidationResult
sealed trait Invalid extends ValidationResult
case object InvalidSignature extends Invalid { def error = "Fail due to invalid input: InvalidSignature" }
case object InvalidClaims extends Invalid { def error = "Fail to Veridy the claims" }
case class InvalidError(error: String) extends Invalid

def verifyPresentation(
key: IssuerPublicKey,
presentation: PresentationJson,
claims: String
): ValidationResult = {
Try {
val verifier = SdjwtVerifierWrapper(
presentation.value, // sd_jwt_presentation
key.pem, // public_key
null, // expected_aud
null, // expected_nonce
SdjwtSerializationFormat.JSON // serialization_format
)
verifier.verify(claims)
} match {
case Failure(ex: SdjwtException.Unspecified) if ex.getMessage() == "invalid input: InvalidSignature" =>
InvalidSignature
case Failure(ex) => InvalidError(ex.getMessage())
case Success(true) => Valid
case Success(false) => InvalidClaims
}
}

/** Verify Presentation with challenge
Expand All @@ -231,15 +253,21 @@ object SDJWT {
expectedNonce: String,
expectedAud: String,
// holderKey: HolderPrivateKey
) = {
val verifier = SdjwtVerifierWrapper(
presentation.value, // sd_jwt_presentation
key.pem, // public_key
expectedAud, // expected_aud
expectedNonce, // expected_nonce
SdjwtSerializationFormat.JSON // serialization_format
)
val result: Boolean = verifier.verify(claims)
result
): ValidationResult = {
Try {
val verifier = SdjwtVerifierWrapper(
presentation.value, // sd_jwt_presentation
key.pem, // public_key
expectedAud, // expected_aud
expectedNonce, // expected_nonce
SdjwtSerializationFormat.JSON // serialization_format
)
verifier.verify(claims)
} match {
case Failure(ex: SdjwtException.Unspecified) if ex.getMessage() == "invalid input: InvalidSignature" =>
InvalidSignature
case Failure(ex) => InvalidError(ex.getMessage())
case Success(presentation) => Valid
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ package org.hyperledger.identus.pollux.sdjwt

import zio.*
import zio.test.*
import zio.test.Assertion.*
import org.hyperledger.identus.pollux.sdjwt.*
import org.hyperledger.identus.shared.crypto.*

import org.bouncycastle.crypto.generators.Ed25519KeyPairGenerator
import org.bouncycastle.crypto.params.Ed25519KeyGenerationParameters
import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters
import java.security.SecureRandom
import java.util.Base64

def ISSUER_KEY = IssuerPrivateKey.fromEcPem(
"""-----BEGIN PRIVATE KEY-----
Expand Down Expand Up @@ -108,23 +108,20 @@ object SDJWTSpec extends ZIOSpecDefault {
},
test("make presentation") {
val credential = SDJWT.issueCredential(ISSUER_KEY, CLAIMS)
val fixme = ISSUER_KEY.signAlg
val presentation = SDJWT.createPresentation(credential, CLAIMS_PRESENTED, fixme)
val presentation = SDJWT.createPresentation(credential, CLAIMS_PRESENTED)
assertTrue(!presentation.value.isEmpty())
},
test("verify presentation") {
val credential = SDJWT.issueCredential(ISSUER_KEY, CLAIMS)
val fixme = ISSUER_KEY.signAlg
val presentation = SDJWT.createPresentation(credential, CLAIMS_PRESENTED, fixme)
val presentation = SDJWT.createPresentation(credential, CLAIMS_PRESENTED)
val ret = SDJWT.verifyPresentation(ISSUER_KEY_PUBLIC, presentation, CLAIMS_PRESENTED)
assertTrue(ret)
assertTrue(ret == SDJWT.Valid)
},
test("fail to verify false claimes presentation") {
val credential = SDJWT.issueCredential(ISSUER_KEY, CLAIMS)
val fixme = ISSUER_KEY.signAlg
val presentation = SDJWT.createPresentation(credential, CLAIMS_PRESENTED, fixme)
val presentation = SDJWT.createPresentation(credential, CLAIMS_PRESENTED)
val ret = SDJWT.verifyPresentation(ISSUER_KEY_PUBLIC, presentation, FAlSE_CLAIMS_PRESENTED)
assertTrue(!ret)
assertTrue(ret == SDJWT.InvalidClaims)
},
// presentation challenge
test("make presentation with holder presentation challenge") {
Expand All @@ -136,7 +133,8 @@ object SDJWTSpec extends ZIOSpecDefault {
"did:example:verifier",
HOLDER_KEY
)
assertTrue(!presentation.value.isEmpty())
assert(presentation.value)(isNonEmptyString)
// Assertion { TestArrow.make[PresentationJson, String] { a => TestTrace.succeed(a.value) } >>> isEmptyString.arrow }
},
test("verify presentation with holder presentation challenge") {
val credential = SDJWT.issueCredential(ISSUER_KEY, CLAIMS, HOLDER_KEY_JWK_PUBLIC)
Expand All @@ -154,7 +152,7 @@ object SDJWTSpec extends ZIOSpecDefault {
expectedNonce = "nonce123456789",
expectedAud = "did:example:verifier",
)
assertTrue(ret)
assertTrue(ret == SDJWT.Valid)
},
test("fail to verify presentation with holder presentation challenge") {
val credential = SDJWT.issueCredential(ISSUER_KEY, CLAIMS)
Expand All @@ -165,8 +163,12 @@ object SDJWTSpec extends ZIOSpecDefault {
aud = "did:example:verifier",
holderKey = HOLDER_KEY
)
val ret = SDJWT.verifyPresentation(ISSUER_KEY_PUBLIC, presentation, FAlSE_CLAIMS_PRESENTED)
assertTrue(!ret)
val ret = SDJWT.verifyPresentation(
ISSUER_KEY_PUBLIC,
presentation,
FAlSE_CLAIMS_PRESENTED,
)
assertTrue(ret == SDJWT.InvalidClaims)
},
test("IssuerPrivateKey from a key type ED25519") {
val ed25519KeyPair = KmpEd25519KeyOps.generateKeyPair
Expand All @@ -192,13 +194,9 @@ object SDJWTSpec extends ZIOSpecDefault {
val issuerPublicKey = IssuerPublicKey(ed25519KeyPair.publicKey)

val credential = SDJWT.issueCredential(issuerKey, CLAIMS)
val presentation = SDJWT.createPresentation(
credential,
CLAIMS_PRESENTED,
issuerKey.signAlg // TODO signAlg should be metadata
)
val presentation = SDJWT.createPresentation(credential, CLAIMS_PRESENTED)
val ret = SDJWT.verifyPresentation(issuerPublicKey, presentation, CLAIMS_PRESENTED)
assertTrue(ret)
assertTrue(ret == SDJWT.Valid)
},
test("Flow with key type ED25519 with presentation challenge") {
val ed25519KeyPair = KmpEd25519KeyOps.generateKeyPair
Expand All @@ -218,46 +216,45 @@ object SDJWTSpec extends ZIOSpecDefault {
aud = "did:example:verifier",
holderKey = holderKey
)
println(presentation)
val ret = SDJWT.verifyPresentation(
key = issuerPublicKey,
presentation = presentation,
claims = CLAIMS_PRESENTED,
expectedNonce = "nonce123456789",
expectedAud = "did:example:verifier"
)

assertTrue(ret)
assertTrue(ret == SDJWT.Valid)
},
// test("Flow with key type ED25519 with presentation challenge fail") {
// val ed25519KeyPair = KmpEd25519KeyOps.generateKeyPair
// val privateKey = ed25519KeyPair.privateKey
// val issuerKey = IssuerPrivateKey(privateKey)
// val issuerPublicKey = IssuerPublicKey(ed25519KeyPair.publicKey)
test("Flow with key type ED25519 with presentation challenge fail") {
val ed25519KeyPair = KmpEd25519KeyOps.generateKeyPair
val privateKey = ed25519KeyPair.privateKey
val issuerKey = IssuerPrivateKey(privateKey)
val issuerPublicKey = IssuerPublicKey(ed25519KeyPair.publicKey)

// val holderEd25519KeyPair = KmpEd25519KeyOps.generateKeyPair
// val holderPrivateKey = holderEd25519KeyPair.privateKey
// val holderKey = HolderPrivateKey(holderPrivateKey)
val holderEd25519KeyPair = KmpEd25519KeyOps.generateKeyPair
// val holderKey = HolderPrivateKey(holderEd25519KeyPair.privateKey)
val holderKeyPublic = HolderPublicKey(holderEd25519KeyPair.publicKey)
val credential = SDJWT.issueCredential(issuerKey, CLAIMS, holderKeyPublic)

// val credential = SDJWT.issueCredential(issuerKey, CLAIMS)
val failHolderEd25519KeyPair = KmpEd25519KeyOps.generateKeyPair
val failHolderKey = HolderPrivateKey(failHolderEd25519KeyPair.privateKey)

// val failHolderKey = HolderPrivateKey(holderPrivateKey)
// val presentation = SDJWT.createPresentation(
// sdjwt = credential,
// claimsToDisclose = CLAIMS_PRESENTED,
// nonce = "nonce123456789",
// aud = "did:example:verifier",
// holderKey = holderKey
// )
// val ret = SDJWT.verifyPresentation(
// key = issuerPublicKey,
// presentation = presentation,
// claims = CLAIMS_PRESENTED,
// expectedNonce = "nonce123456789",
// expectedAud = failHolderKey
// )
// assertTrue(ret)
// },
val presentation = SDJWT.createPresentation(
sdjwt = credential,
claimsToDisclose = CLAIMS_PRESENTED,
nonce = "nonce123456789",
aud = "did:example:verifier",
holderKey = failHolderKey
)
val ret = SDJWT.verifyPresentation(
key = issuerPublicKey,
presentation = presentation,
claims = CLAIMS_PRESENTED,
expectedNonce = "nonce123456789",
expectedAud = "did:example:verifier"
)
assertTrue(ret == SDJWT.InvalidSignature)
},
)

}

0 comments on commit 87f72bd

Please sign in to comment.