From b8afabb256ba4da57c4fb2f398020a7ea484b6e5 Mon Sep 17 00:00:00 2001 From: Simon Mueller Date: Thu, 14 Dec 2023 10:30:10 +0100 Subject: [PATCH] Refactor Test cases --- .../src/main/kotlin/VcLibVersions.kt | 2 +- kmp-crypto | 2 +- vclib-aries/build.gradle.kts | 8 +- .../wallet/lib/aries/PresentProofProtocol.kt | 2 +- vclib-openid/build.gradle.kts | 15 +- .../wallet/lib/oidc/OidcSiopVerifier.kt | 2 +- .../wallet/lib/oidc/OidcSiopWallet.kt | 2 +- .../wallet/lib/oidvci/IssuerService.kt | 2 +- .../wallet/lib/oidvci/WalletService.kt | 3 +- vclib/build.gradle.kts | 15 +- .../wallet/lib/agent/CryptoService.kt | 4 +- .../asitplus/wallet/lib/cbor/CoseService.kt | 2 +- .../at/asitplus/wallet/lib/jws/JwsService.kt | 21 +- .../wallet/lib/agent/ValidatorVcTest.kt | 2 +- .../lib/jws/JwsHeaderSerializationTest.kt | 2 +- .../asitplus/wallet/lib/jws/JwsServiceTest.kt | 2 +- .../wallet/lib/agent/DefaultCryptoService.kt | 28 +- .../wallet/lib/jws/JwsServiceJvmTest.kt | 296 +++++++++++++----- 18 files changed, 270 insertions(+), 140 deletions(-) diff --git a/conventions-vclib/src/main/kotlin/VcLibVersions.kt b/conventions-vclib/src/main/kotlin/VcLibVersions.kt index 30518364b..17d4a98c0 100644 --- a/conventions-vclib/src/main/kotlin/VcLibVersions.kt +++ b/conventions-vclib/src/main/kotlin/VcLibVersions.kt @@ -3,7 +3,7 @@ object VcLibVersions { const val resultlib = "1.5.3" const val encoding = "1.2.3" const val okio = "3.5.0" - const val kmpcrypto = "1.0-SNAPSHOT" + const val kmpcrypto = "2.2.0-SNAPSHOT" object Jvm { const val `jose-jwt` = "9.31" diff --git a/kmp-crypto b/kmp-crypto index 897271b57..bcc014865 160000 --- a/kmp-crypto +++ b/kmp-crypto @@ -1 +1 @@ -Subproject commit 897271b57d7638fd2bac40d1b582b728fab375b9 +Subproject commit bcc014865bd71af65526b0865ed86b9e66abf621 diff --git a/vclib-aries/build.gradle.kts b/vclib-aries/build.gradle.kts index f00cbdceb..f1042ab31 100644 --- a/vclib-aries/build.gradle.kts +++ b/vclib-aries/build.gradle.kts @@ -13,12 +13,16 @@ val artifactVersion: String by extra group = "at.asitplus.wallet" version = artifactVersion +val iosDisabled: String? by extra + kotlin { jvm() - iosArm64() + if (iosDisabled != "true") { + iosArm64() iosSimulatorArm64() iosX64() +} sourceSets { commonMain { dependencies { @@ -41,7 +45,7 @@ kotlin { } } } -exportIosFramework("VcLibAriesKmm", *commonIosExports(), project(":vclib")) +if (iosDisabled != "true") exportIosFramework("VcLibAriesKmm", *commonIosExports(), project(":vclib")) val javadocJar = setupDokka(baseUrl = "https://github.com/a-sit-plus/kmm-vc-library/tree/main/", multiModuleDoc = true) diff --git a/vclib-aries/src/commonMain/kotlin/at/asitplus/wallet/lib/aries/PresentProofProtocol.kt b/vclib-aries/src/commonMain/kotlin/at/asitplus/wallet/lib/aries/PresentProofProtocol.kt index e640ba582..6bd764bf9 100644 --- a/vclib-aries/src/commonMain/kotlin/at/asitplus/wallet/lib/aries/PresentProofProtocol.kt +++ b/vclib-aries/src/commonMain/kotlin/at/asitplus/wallet/lib/aries/PresentProofProtocol.kt @@ -1,6 +1,6 @@ package at.asitplus.wallet.lib.aries -import at.asitplus.crypto.datatypes.JwsAlgorithm +import at.asitplus.crypto.datatypes.jws.JwsAlgorithm import at.asitplus.crypto.datatypes.jws.JsonWebKey import at.asitplus.wallet.lib.agent.Holder import at.asitplus.wallet.lib.agent.Verifier diff --git a/vclib-openid/build.gradle.kts b/vclib-openid/build.gradle.kts index 8d40788bf..e6f769683 100644 --- a/vclib-openid/build.gradle.kts +++ b/vclib-openid/build.gradle.kts @@ -14,15 +14,21 @@ group = "at.asitplus.wallet" version = artifactVersion +val iosDisabled: String? by extra + + kotlin { jvm() - iosArm64() - iosSimulatorArm64() - iosX64() + if (iosDisabled != "true") { + iosArm64() + iosSimulatorArm64() + iosX64() + } sourceSets { commonMain { dependencies { commonImplementationDependencies() + api("at.asitplus.crypto:datatypes-jws:${VcLibVersions.kmpcrypto}") api(project(":vclib")) } } @@ -41,7 +47,8 @@ kotlin { } } -exportIosFramework("VcLibOpenIdKmm", *commonIosExports(), project(":vclib")) +if (iosDisabled != "true") exportIosFramework("VcLibOpenIdKmm", *commonIosExports(), project(":vclib")) + val javadocJar = setupDokka(baseUrl = "https://github.com/a-sit-plus/kmm-vc-library/tree/main/", multiModuleDoc = true) publishing { diff --git a/vclib-openid/src/commonMain/kotlin/at/asitplus/wallet/lib/oidc/OidcSiopVerifier.kt b/vclib-openid/src/commonMain/kotlin/at/asitplus/wallet/lib/oidc/OidcSiopVerifier.kt index 719610b9a..390e8346a 100644 --- a/vclib-openid/src/commonMain/kotlin/at/asitplus/wallet/lib/oidc/OidcSiopVerifier.kt +++ b/vclib-openid/src/commonMain/kotlin/at/asitplus/wallet/lib/oidc/OidcSiopVerifier.kt @@ -1,7 +1,7 @@ package at.asitplus.wallet.lib.oidc import at.asitplus.crypto.datatypes.CryptoPublicKey -import at.asitplus.crypto.datatypes.JwsAlgorithm +import at.asitplus.crypto.datatypes.jws.JwsAlgorithm import at.asitplus.crypto.datatypes.jws.JwsHeader import at.asitplus.crypto.datatypes.jws.JwsSigned import at.asitplus.crypto.datatypes.jws.toJsonWebKey diff --git a/vclib-openid/src/commonMain/kotlin/at/asitplus/wallet/lib/oidc/OidcSiopWallet.kt b/vclib-openid/src/commonMain/kotlin/at/asitplus/wallet/lib/oidc/OidcSiopWallet.kt index f8943aedf..49e58e526 100644 --- a/vclib-openid/src/commonMain/kotlin/at/asitplus/wallet/lib/oidc/OidcSiopWallet.kt +++ b/vclib-openid/src/commonMain/kotlin/at/asitplus/wallet/lib/oidc/OidcSiopWallet.kt @@ -2,7 +2,7 @@ package at.asitplus.wallet.lib.oidc import at.asitplus.KmmResult import at.asitplus.crypto.datatypes.CryptoPublicKey -import at.asitplus.crypto.datatypes.JwsAlgorithm +import at.asitplus.crypto.datatypes.jws.JwsAlgorithm import at.asitplus.crypto.datatypes.jws.JwsHeader import at.asitplus.crypto.datatypes.jws.JwsSigned import at.asitplus.crypto.datatypes.jws.toJsonWebKey diff --git a/vclib-openid/src/commonMain/kotlin/at/asitplus/wallet/lib/oidvci/IssuerService.kt b/vclib-openid/src/commonMain/kotlin/at/asitplus/wallet/lib/oidvci/IssuerService.kt index f35322063..b08c41bcd 100644 --- a/vclib-openid/src/commonMain/kotlin/at/asitplus/wallet/lib/oidvci/IssuerService.kt +++ b/vclib-openid/src/commonMain/kotlin/at/asitplus/wallet/lib/oidvci/IssuerService.kt @@ -1,6 +1,6 @@ package at.asitplus.wallet.lib.oidvci -import at.asitplus.crypto.datatypes.JwsAlgorithm +import at.asitplus.crypto.datatypes.jws.JwsAlgorithm import at.asitplus.crypto.datatypes.cose.toCoseKey import at.asitplus.crypto.datatypes.io.Base64UrlStrict import at.asitplus.crypto.datatypes.jws.JsonWebToken diff --git a/vclib-openid/src/commonMain/kotlin/at/asitplus/wallet/lib/oidvci/WalletService.kt b/vclib-openid/src/commonMain/kotlin/at/asitplus/wallet/lib/oidvci/WalletService.kt index 150446697..5a51c663f 100644 --- a/vclib-openid/src/commonMain/kotlin/at/asitplus/wallet/lib/oidvci/WalletService.kt +++ b/vclib-openid/src/commonMain/kotlin/at/asitplus/wallet/lib/oidvci/WalletService.kt @@ -2,6 +2,7 @@ package at.asitplus.wallet.lib.oidvci import at.asitplus.crypto.datatypes.jws.JsonWebToken import at.asitplus.crypto.datatypes.jws.JwsHeader +import at.asitplus.crypto.datatypes.jws.toJwsAlgorithm import at.asitplus.wallet.lib.agent.CryptoService import at.asitplus.wallet.lib.agent.DefaultCryptoService import at.asitplus.wallet.lib.data.ConstantIndex @@ -91,7 +92,7 @@ class WalletService( proofType = OpenIdConstants.ProofTypes.JWT, jwt = jwsService.createSignedJwsAddingParams( header = JwsHeader( - algorithm = cryptoService.algorithm, + algorithm = cryptoService.algorithm.toJwsAlgorithm(), type = OpenIdConstants.ProofTypes.JWT_HEADER_TYPE, ), payload = JsonWebToken( diff --git a/vclib/build.gradle.kts b/vclib/build.gradle.kts index 75076e5fe..b99a7d5e6 100644 --- a/vclib/build.gradle.kts +++ b/vclib/build.gradle.kts @@ -14,11 +14,17 @@ val artifactVersion: String by extra group = "at.asitplus.wallet" version = artifactVersion + +val iosDisabled: String? by extra + + kotlin { jvm() - iosArm64() - iosSimulatorArm64() - iosX64() + if (iosDisabled != "true") { + iosArm64() + iosSimulatorArm64() + iosX64() + } sourceSets { commonMain { @@ -48,8 +54,7 @@ kotlin { } } } - -exportIosFramework("VcLibKmm", *commonIosExports()) +if (iosDisabled != "true") exportIosFramework("VcLibKmm", *commonIosExports()) val javadocJar = setupDokka(baseUrl = "https://github.com/a-sit-plus/kmm-vc-library/tree/main/", multiModuleDoc = true) diff --git a/vclib/src/commonMain/kotlin/at/asitplus/wallet/lib/agent/CryptoService.kt b/vclib/src/commonMain/kotlin/at/asitplus/wallet/lib/agent/CryptoService.kt index 60a4dc600..4ffb6eebe 100644 --- a/vclib/src/commonMain/kotlin/at/asitplus/wallet/lib/agent/CryptoService.kt +++ b/vclib/src/commonMain/kotlin/at/asitplus/wallet/lib/agent/CryptoService.kt @@ -41,7 +41,7 @@ interface CryptoService { fun messageDigest(input: ByteArray, digest: Digest): KmmResult - val algorithm: JwsAlgorithm + val algorithm: CryptoAlgorithm val publicKey: CryptoPublicKey @@ -63,7 +63,7 @@ interface VerifierCryptoService { fun verify( input: ByteArray, signature: CryptoSignature, - algorithm: JwsAlgorithm, + algorithm: CryptoAlgorithm, publicKey: CryptoPublicKey, ): KmmResult diff --git a/vclib/src/commonMain/kotlin/at/asitplus/wallet/lib/cbor/CoseService.kt b/vclib/src/commonMain/kotlin/at/asitplus/wallet/lib/cbor/CoseService.kt index d3cd9204c..fae41c615 100644 --- a/vclib/src/commonMain/kotlin/at/asitplus/wallet/lib/cbor/CoseService.kt +++ b/vclib/src/commonMain/kotlin/at/asitplus/wallet/lib/cbor/CoseService.kt @@ -116,7 +116,7 @@ class DefaultVerifierCoseService( val verified = cryptoService.verify( input = signatureInput, signature = coseSigned.signature, - algorithm = algorithm.toJwsAlgorithm(), + algorithm = algorithm.toCryptoAlgorithm(), publicKey = publicKey ) val result = verified.getOrElse { diff --git a/vclib/src/commonMain/kotlin/at/asitplus/wallet/lib/jws/JwsService.kt b/vclib/src/commonMain/kotlin/at/asitplus/wallet/lib/jws/JwsService.kt index 05d571c26..4aadee843 100644 --- a/vclib/src/commonMain/kotlin/at/asitplus/wallet/lib/jws/JwsService.kt +++ b/vclib/src/commonMain/kotlin/at/asitplus/wallet/lib/jws/JwsService.kt @@ -68,7 +68,7 @@ class DefaultJwsService(private val cryptoService: CryptoService) : JwsService { contentType: String? ): JwsSigned? { val jwsHeader = JwsHeader( - algorithm = cryptoService.algorithm, + algorithm = cryptoService.algorithm.toJwsAlgorithm(), keyId = cryptoService.publicKey.keyId, type = type, contentType = contentType @@ -77,7 +77,7 @@ class DefaultJwsService(private val cryptoService: CryptoService) : JwsService { } override suspend fun createSignedJws(header: JwsHeader, payload: ByteArray): JwsSigned? { - if (header.algorithm != cryptoService.algorithm + if (header.algorithm != cryptoService.algorithm.toJwsAlgorithm() || header.keyId?.let { it != cryptoService.publicKey.keyId } == true || header.jsonWebKey?.let { it != cryptoService.jsonWebKey } == true ) { @@ -98,7 +98,7 @@ class DefaultJwsService(private val cryptoService: CryptoService) : JwsService { addKeyId: Boolean, addJsonWebKey: Boolean ): JwsSigned? { - var copy = header.copy(algorithm = cryptoService.algorithm) + var copy = header.copy(algorithm = cryptoService.algorithm.toJwsAlgorithm()) if (addKeyId) copy = copy.copy(keyId = cryptoService.publicKey.keyId) if (addJsonWebKey) @@ -219,15 +219,14 @@ class DefaultVerifierJwsService( val verified = cryptoService.verify( input = jwsObject.plainSignatureInput.encodeToByteArray(), signature = jwsObject.signature, - algorithm = header.algorithm, + algorithm = header.algorithm.toCryptoAlgorithm(), publicKey = publicKey ) -// val falseVar = false //workaround kotlin bug for linking xcframework -// return verified.getOrElse { -// Napier.w("No verification from native code", it) -// falseVar -// } - return verified.getOrThrow() + val falseVar = false //workaround kotlin bug for linking xcframework + return verified.getOrElse { + Napier.w("No verification from native code", it) + falseVar + } } /** @@ -240,7 +239,7 @@ class DefaultVerifierJwsService( val verified = cryptoService.verify( jwsObject.plainSignatureInput.encodeToByteArray(), jwsObject.signature, - jwsObject.header.algorithm, + jwsObject.header.algorithm.toCryptoAlgorithm(), publicKey, ) val falseVar = false //workaround kotlin bug for linking xcframework diff --git a/vclib/src/commonTest/kotlin/at/asitplus/wallet/lib/agent/ValidatorVcTest.kt b/vclib/src/commonTest/kotlin/at/asitplus/wallet/lib/agent/ValidatorVcTest.kt index 3b339390a..40c29f73f 100644 --- a/vclib/src/commonTest/kotlin/at/asitplus/wallet/lib/agent/ValidatorVcTest.kt +++ b/vclib/src/commonTest/kotlin/at/asitplus/wallet/lib/agent/ValidatorVcTest.kt @@ -1,6 +1,6 @@ package at.asitplus.wallet.lib.agent -import at.asitplus.crypto.datatypes.JwsAlgorithm +import at.asitplus.crypto.datatypes.jws.JwsAlgorithm import at.asitplus.crypto.datatypes.jws.JwsContentTypeConstants import at.asitplus.crypto.datatypes.jws.JwsHeader import at.asitplus.crypto.datatypes.jws.JwsSigned diff --git a/vclib/src/commonTest/kotlin/at/asitplus/wallet/lib/jws/JwsHeaderSerializationTest.kt b/vclib/src/commonTest/kotlin/at/asitplus/wallet/lib/jws/JwsHeaderSerializationTest.kt index d9d5dc880..ec6bb72b6 100644 --- a/vclib/src/commonTest/kotlin/at/asitplus/wallet/lib/jws/JwsHeaderSerializationTest.kt +++ b/vclib/src/commonTest/kotlin/at/asitplus/wallet/lib/jws/JwsHeaderSerializationTest.kt @@ -1,7 +1,7 @@ package at.asitplus.wallet.lib.jws -import at.asitplus.crypto.datatypes.JwsAlgorithm +import at.asitplus.crypto.datatypes.jws.JwsAlgorithm import at.asitplus.crypto.datatypes.io.Base64Strict import at.asitplus.crypto.datatypes.jws.JwsContentTypeConstants import at.asitplus.crypto.datatypes.jws.JwsHeader diff --git a/vclib/src/commonTest/kotlin/at/asitplus/wallet/lib/jws/JwsServiceTest.kt b/vclib/src/commonTest/kotlin/at/asitplus/wallet/lib/jws/JwsServiceTest.kt index 81e5cc0f0..2a0a57953 100644 --- a/vclib/src/commonTest/kotlin/at/asitplus/wallet/lib/jws/JwsServiceTest.kt +++ b/vclib/src/commonTest/kotlin/at/asitplus/wallet/lib/jws/JwsServiceTest.kt @@ -1,6 +1,6 @@ package at.asitplus.wallet.lib.jws -import at.asitplus.crypto.datatypes.JwsAlgorithm +import at.asitplus.crypto.datatypes.jws.JwsAlgorithm import at.asitplus.crypto.datatypes.jws.* import at.asitplus.wallet.lib.agent.CryptoService import at.asitplus.wallet.lib.agent.DefaultCryptoService diff --git a/vclib/src/jvmMain/kotlin/at/asitplus/wallet/lib/agent/DefaultCryptoService.kt b/vclib/src/jvmMain/kotlin/at/asitplus/wallet/lib/agent/DefaultCryptoService.kt index a27e256f9..0f1a2bbdc 100644 --- a/vclib/src/jvmMain/kotlin/at/asitplus/wallet/lib/agent/DefaultCryptoService.kt +++ b/vclib/src/jvmMain/kotlin/at/asitplus/wallet/lib/agent/DefaultCryptoService.kt @@ -40,7 +40,7 @@ actual open class DefaultCryptoService : CryptoService { private val privateKey: PrivateKey - final override val algorithm: JwsAlgorithm + final override val algorithm: CryptoAlgorithm final override val publicKey: CryptoPublicKey @@ -57,7 +57,7 @@ actual open class DefaultCryptoService : CryptoService { val keyPair = KeyPairGenerator.getInstance("EC").also { it.initialize(SECP_256_R_1.keyLengthBits.toInt()) }.genKeyPair() this.privateKey = keyPair.private - this.algorithm = JwsAlgorithm.ES256 + this.algorithm = CryptoAlgorithm.ES256 this.publicKey = CryptoPublicKey.fromJcaPublicKey(keyPair.public).getOrThrow() this.jsonWebKey = publicKey.toJsonWebKey().getOrThrow() this.coseKey = publicKey.toCoseKey(algorithm.toCoseAlgorithm()).getOrThrow() @@ -70,7 +70,7 @@ actual open class DefaultCryptoService : CryptoService { * it's mandatory * Also used for custom certificates */ - constructor(keyPair: KeyPair, algorithm: JwsAlgorithm, certificate: Certificate? = null) { + constructor(keyPair: KeyPair, algorithm: CryptoAlgorithm, certificate: Certificate? = null) { this.privateKey = keyPair.private this.algorithm = algorithm this.publicKey = CryptoPublicKey.fromJcaPublicKey(keyPair.public).getOrThrow() @@ -105,29 +105,15 @@ actual open class DefaultCryptoService : CryptoService { return X509Certificate(tbsCertificate, algorithm, signature) } - // override suspend fun sign(input: ByteArray): KmmResult = -// runCatching { -// Signature.getInstance(algorithm.jcaName).apply { -// initSign(privateKey) -// update(input) -// }.sign() -// }.wrap().mapCatching { -//// when (algorithm) { -//// JwsAlgorithm.ES256, JwsAlgorithm.ES384, JwsAlgorithm.ES512 -> CryptoSignature.EC(it) -//// else -> CryptoSignature.RSAorHMAC(it) -//// } -// CryptoSignature.decodeFromDer(it) -// } override suspend fun sign(input: ByteArray): KmmResult = runCatching { val sig = Signature.getInstance(algorithm.jcaName).apply { initSign(privateKey) update(input) }.sign() - val test = sig.encodeToString(Base64UrlStrict) - println(test) - CryptoSignature.decodeFromDer(sig) - }.wrap().also { it.getOrThrow() } + val res = if (algorithm.name.take(2) == "ES") CryptoSignature.decodeFromDer(sig) else CryptoSignature.RSAorHMAC(sig) //In Java EC signatures are returned as DER-encoded, RSA signatures however are raw bytearrays + res + }.wrap() override fun encrypt( key: ByteArray, iv: ByteArray, aad: ByteArray, input: ByteArray, algorithm: JweEncryption @@ -207,7 +193,7 @@ actual open class DefaultVerifierCryptoService : VerifierCryptoService { override fun verify( input: ByteArray, signature: CryptoSignature, - algorithm: JwsAlgorithm, + algorithm: CryptoAlgorithm, publicKey: CryptoPublicKey, ): KmmResult = runCatching { diff --git a/vclib/src/jvmTest/kotlin/at/asitplus/wallet/lib/jws/JwsServiceJvmTest.kt b/vclib/src/jvmTest/kotlin/at/asitplus/wallet/lib/jws/JwsServiceJvmTest.kt index c7ae9c586..0ec16892f 100644 --- a/vclib/src/jvmTest/kotlin/at/asitplus/wallet/lib/jws/JwsServiceJvmTest.kt +++ b/vclib/src/jvmTest/kotlin/at/asitplus/wallet/lib/jws/JwsServiceJvmTest.kt @@ -1,129 +1,257 @@ package at.asitplus.wallet.lib.jws -import at.asitplus.crypto.datatypes.JwsAlgorithm -import at.asitplus.crypto.datatypes.jws.* +import at.asitplus.crypto.datatypes.CryptoAlgorithm +import at.asitplus.crypto.datatypes.io.Base64UrlStrict +import at.asitplus.crypto.datatypes.jws.JwsContentTypeConstants +import at.asitplus.crypto.datatypes.jws.JwsSigned import at.asitplus.wallet.lib.agent.CryptoService import at.asitplus.wallet.lib.agent.DefaultCryptoService import at.asitplus.wallet.lib.data.jsonSerializer import com.benasher44.uuid.uuid4 import com.nimbusds.jose.* -import com.nimbusds.jose.crypto.ECDHDecrypter -import com.nimbusds.jose.crypto.ECDHEncrypter import com.nimbusds.jose.crypto.ECDSASigner import com.nimbusds.jose.crypto.ECDSAVerifier +import com.nimbusds.jose.crypto.RSASSASigner +import com.nimbusds.jose.crypto.RSASSAVerifier +import io.kotest.assertions.withClue import io.kotest.core.spec.style.FreeSpec -import io.kotest.datatest.withData -import io.kotest.matchers.nulls.shouldBeNull import io.kotest.matchers.nulls.shouldNotBeNull import io.kotest.matchers.shouldBe -import io.kotest.mpp.timeInMillis +import io.matthewnelson.encoding.core.Encoder.Companion.encodeToString import kotlinx.serialization.encodeToString import java.security.KeyPair import java.security.KeyPairGenerator import java.security.interfaces.ECPrivateKey import java.security.interfaces.ECPublicKey +import java.security.interfaces.RSAPrivateKey +import java.security.interfaces.RSAPublicKey +import kotlin.random.Random class JwsServiceJvmTest : FreeSpec({ - lateinit var cryptoService: CryptoService - lateinit var jwsService: JwsService - lateinit var verifierJwsService: VerifierJwsService - lateinit var randomPayload: String - lateinit var publicKeyDesc: List> - - "EC" - { - withData(256, 384, 521) { bits -> - publicKeyDesc = List>(5) { - val keyPair = KeyPairGenerator.getInstance("EC").apply { - initialize(bits) - }.genKeyPair() - val algo = when (bits) { - 256 -> JwsAlgorithm.ES256 - 384 -> JwsAlgorithm.ES384 - 521 -> JwsAlgorithm.ES512 - else -> JwsAlgorithm.NON_JWS_SHA1_WITH_RSA.also { throw IllegalArgumentException("Unknown EC Curve size") } // necessary(compiler), but redundant else-branch + val configurations: List> = + listOf( + ("EC" to 256), + ("EC" to 384), + ("EC" to 521), +// ("RSA" to 512), // JOSE does not allow key sizes < 2048 +// ("RSA" to 1024), + ("RSA" to 2048), + ("RSA" to 3072), + ("RSA" to 4096) + ) + val rsaVersions: MutableList = mutableListOf( + CryptoAlgorithm.RS256, + CryptoAlgorithm.RS384, + CryptoAlgorithm.RS512, + CryptoAlgorithm.PS256, + CryptoAlgorithm.PS384, + CryptoAlgorithm.PS512 + ) + + configurations.forEach { thisConfiguration -> + repeat(2) { number -> + val keyPair = KeyPairGenerator.getInstance(thisConfiguration.first).apply { + initialize(thisConfiguration.second) + }.genKeyPair() + + val algo = when (thisConfiguration.first) { + "EC" -> when (thisConfiguration.second) { + 256 -> CryptoAlgorithm.ES256 + 384 -> CryptoAlgorithm.ES384 + 521 -> CryptoAlgorithm.ES512 + else -> throw IllegalArgumentException("Unknown EC Curve size") // necessary(compiler), but otherwise redundant else-branch + } + + "RSA" -> { + val rndIndex = Random.nextInt(rsaVersions.size) + rsaVersions.removeAt(rndIndex) // because tests are repeated twice this returns a random matching of hash-function to key-size } - Pair(keyPair, algo) + + else -> throw IllegalArgumentException("Unknown Key Type") // -||- } - withData(publicKeyDesc) { (keyPair, algorithm) -> - cryptoService = DefaultCryptoService(keyPair, algorithm) - jwsService = DefaultJwsService(cryptoService) - verifierJwsService = DefaultVerifierJwsService() - randomPayload = uuid4().toString() - withData("signed object from ext. library can be verified: $algorithm", Pair(keyPair, algorithm)) { + val jvmVerifier = + if (algo.name.take(2) == "ES") ECDSAVerifier(keyPair.public as ECPublicKey) + else RSASSAVerifier(keyPair.public as RSAPublicKey) + val jvmSigner = + if (algo.name.take(2) == "ES") ECDSASigner(keyPair.private as ECPrivateKey) + else RSASSASigner(keyPair.private as RSAPrivateKey) + + val cryptoService = DefaultCryptoService(keyPair, algo) + val jwsService = DefaultJwsService(cryptoService) + val verifierJwsService = DefaultVerifierJwsService() + val randomPayload = uuid4().toString() + + val testIdentifier = "$algo, ${thisConfiguration.second}, ${number + 1}" + + "$testIdentifier:" - { + + "Signed object from int. library can be verified with int. library" { val stringPayload = jsonSerializer.encodeToString(randomPayload) -// if (algorithm == JwsAlgorithm.ES512){ -// print(stringPayload) -// } - val libHeader = JWSHeader.Builder(JWSAlgorithm(algorithm.name)).type(JOSEObjectType("JWT")) + val signed = + jwsService.createSignedJwt(JwsContentTypeConstants.JWT, stringPayload.encodeToByteArray()) + signed.shouldNotBeNull() + val selfVerify = verifierJwsService.verifyJwsObject(signed) + withClue("$algo: Signature: ${signed.signature.serialize()}"){ + selfVerify shouldBe true + } + } + + "Signed object from ext. library can be verified with int. library" { + val stringPayload = jsonSerializer.encodeToString(randomPayload) + val libHeader = JWSHeader.Builder(JWSAlgorithm(algo.name)).type(JOSEObjectType("JWT")) .keyID(cryptoService.jsonWebKey.keyId).build() val libObject = JWSObject(libHeader, Payload(stringPayload)).also { - it.sign(ECDSASigner(keyPair.private as ECPrivateKey)) + it.sign(jvmSigner) } - libObject.verify(ECDSAVerifier(keyPair.public as ECPublicKey)) shouldBe true + libObject.verify(jvmVerifier) shouldBe true // Parsing to our structure verifying payload val signedLibObject = libObject.serialize() val parsedJwsSigned = JwsSigned.parse(signedLibObject) parsedJwsSigned.shouldNotBeNull() parsedJwsSigned.payload.decodeToString() shouldBe stringPayload - val parsedSig = parsedJwsSigned.signature.serialize() - // verifying external JWT with our service - val result = verifierJwsService.verifyJwsObject(parsedJwsSigned) - result shouldBe true - } - - withData("signed object can be verified with ext. library: $algorithm", Pair(keyPair, algorithm)) { - val stringPayload = jsonSerializer.encodeToString(randomPayload) - val signed = jwsService.createSignedJwt(JwsContentTypeConstants.JWT, stringPayload.encodeToByteArray()) - - verifierJwsService.verifyJwsObject(signed!!) shouldBe true - val parsed = JWSObject.parse(signed.serialize()) - parsed.shouldNotBeNull() - parsed.payload.toString() shouldBe stringPayload - val result = parsed.verify(ECDSAVerifier(keyPair.public as ECPublicKey)) - result shouldBe true - } + val parsedSig = parsedJwsSigned.signature.rawByteArray.encodeToString(Base64UrlStrict) - withData("encrypted object from ext. library can be decrypted: $algorithm", Pair(keyPair, algorithm)) { - val stringPayload = jsonSerializer.encodeToString(randomPayload) - val libJweHeader = JWEHeader.Builder(JWEAlgorithm.ECDH_ES, EncryptionMethod.A256GCM) - .type(JOSEObjectType(JwsContentTypeConstants.DIDCOMM_ENCRYPTED_JSON)) - .contentType(JwsContentTypeConstants.DIDCOMM_PLAIN_JSON).keyID(cryptoService.jsonWebKey.keyId) - .build() - val libJweObject = JWEObject(libJweHeader, Payload(stringPayload)).also { - it.encrypt(ECDHEncrypter(keyPair.public as ECPublicKey)) + withClue( + "$algo: \nSignatures should match\n" + + "Ours:\n" + + "$parsedSig\n" + + "Theirs:\n" + + "${libObject.signature}" + ) { + parsedSig shouldBe libObject.signature.toString() } - val encryptedJwe = libJweObject.serialize() - - val parsedJwe = JweEncrypted.parse(encryptedJwe) - parsedJwe.shouldNotBeNull() - jwsService.decryptJweObject( - parsedJwe, encryptedJwe - )?.payload?.decodeToString() shouldBe stringPayload + withClue("$algo: Signature: ${parsedJwsSigned.signature.serialize()}") { + val result = verifierJwsService.verifyJwsObject(parsedJwsSigned) + result shouldBe true + } } - withData("encrypted object can be decrypted with ext. library: $algorithm", Pair(keyPair, algorithm)) { + "Signed object from int. library can be verified with ext. library" { val stringPayload = jsonSerializer.encodeToString(randomPayload) - val encrypted = jwsService.encryptJweObject( - JwsContentTypeConstants.DIDCOMM_ENCRYPTED_JSON, - stringPayload.encodeToByteArray(), - cryptoService.jsonWebKey, - JwsContentTypeConstants.DIDCOMM_PLAIN_JSON, - JweAlgorithm.ECDH_ES, - JweEncryption.A256GCM, - ) - - val parsed = JWEObject.parse(encrypted) + val signed = + jwsService.createSignedJwt(JwsContentTypeConstants.JWT, stringPayload.encodeToByteArray()) + signed.shouldNotBeNull() + val parsed = JWSObject.parse(signed.serialize()) parsed.shouldNotBeNull() - parsed.payload.shouldBeNull() - - parsed.decrypt(ECDHDecrypter(keyPair.private as ECPrivateKey)) parsed.payload.toString() shouldBe stringPayload + val result = parsed.verify(jvmVerifier) + withClue("$algo: Signature: ${parsed.signature}") { + result shouldBe true + } } } } } -}) +// +// "EC" - { +// withData(256, 384, 521) +// { bits -> +// publicKeyDesc = List>(5) { +// val keyPair = KeyPairGenerator.getInstance("EC").apply { +// initialize(bits) +// }.genKeyPair() +// val algo = when (bits) { +// 256 -> CryptoAlgorithm.ES256 +// 384 -> CryptoAlgorithm.ES384 +// 521 -> CryptoAlgorithm.ES512 +// else -> CryptoAlgorithm.RS1.also { throw IllegalArgumentException("Unknown EC Curve size") } // necessary(compiler), but otherwise redundant else-branch +// } +// Pair(keyPair, algo) +// } +// withData(publicKeyDesc) { (keyPair, algorithm) -> +// cryptoService = DefaultCryptoService(keyPair, algorithm) +// jwsService = DefaultJwsService(cryptoService) +// verifierJwsService = DefaultVerifierJwsService() +// randomPayload = uuid4().toString() +// +// withData("signed object from ext. library can be verified: $algorithm", Pair(keyPair, algorithm)) { +// val stringPayload = jsonSerializer.encodeToString(randomPayload) +// val libHeader = JWSHeader.Builder(JWSAlgorithm(algorithm.name)).type(JOSEObjectType("JWT")) +// .keyID(cryptoService.jsonWebKey.keyId).build() +// val libObject = JWSObject(libHeader, Payload(stringPayload)).also { +// it.sign(ECDSASigner(keyPair.private as ECPrivateKey)) +// } +// libObject.verify(ECDSAVerifier(keyPair.public as ECPublicKey)) shouldBe true +// +// // Parsing to our structure verifying payload +// val signedLibObject = libObject.serialize() +// val parsedJwsSigned = JwsSigned.parse(signedLibObject) +// parsedJwsSigned.shouldNotBeNull() +// parsedJwsSigned.payload.decodeToString() shouldBe stringPayload +// val parsedSig = parsedJwsSigned.signature.rawByteArray.encodeToString(Base64UrlStrict) +// +// withClue( +// "Signatures should match\n" + +// "Ours:\n" + +// "$parsedSig\n" + +// "Theirs:\n" + +// "${libObject.signature}" +// ) { +// parsedSig shouldBe libObject.signature.toString() +// } +// +// // verifying external JWT with our service +// withClue("Signature is valid") { +// val result = verifierJwsService.verifyJwsObject(parsedJwsSigned) +// result shouldBe true +// } +// } +// +// withData("signed object can be verified with ext. library: $algorithm", Pair(keyPair, algorithm)) { +// val stringPayload = jsonSerializer.encodeToString(randomPayload) +// val signed = +// jwsService.createSignedJwt(JwsContentTypeConstants.JWT, stringPayload.encodeToByteArray()) +// +// verifierJwsService.verifyJwsObject(signed!!) shouldBe true +// val parsed = JWSObject.parse(signed.serialize()) +// parsed.shouldNotBeNull() +// parsed.payload.toString() shouldBe stringPayload +// val result = parsed.verify(ECDSAVerifier(keyPair.public as ECPublicKey)) +// result shouldBe true +// } +// +// withData("encrypted object from ext. library can be decrypted: $algorithm", Pair(keyPair, algorithm)) { +// val stringPayload = jsonSerializer.encodeToString(randomPayload) +// val libJweHeader = JWEHeader.Builder(JWEAlgorithm.ECDH_ES, EncryptionMethod.A256GCM) +// .type(JOSEObjectType(JwsContentTypeConstants.DIDCOMM_ENCRYPTED_JSON)) +// .contentType(JwsContentTypeConstants.DIDCOMM_PLAIN_JSON).keyID(cryptoService.jsonWebKey.keyId) +// .build() +// val libJweObject = JWEObject(libJweHeader, Payload(stringPayload)).also { +// it.encrypt(ECDHEncrypter(keyPair.public as ECPublicKey)) +// } +// val encryptedJwe = libJweObject.serialize() +// +// val parsedJwe = JweEncrypted.parse(encryptedJwe) +// parsedJwe.shouldNotBeNull() +// +// jwsService.decryptJweObject( +// parsedJwe, encryptedJwe +// )?.payload?.decodeToString() shouldBe stringPayload +// } +// +// withData("encrypted object can be decrypted with ext. library: $algorithm", Pair(keyPair, algorithm)) { +// val stringPayload = jsonSerializer.encodeToString(randomPayload) +// val encrypted = jwsService.encryptJweObject( +// JwsContentTypeConstants.DIDCOMM_ENCRYPTED_JSON, +// stringPayload.encodeToByteArray(), +// cryptoService.jsonWebKey, +// JwsContentTypeConstants.DIDCOMM_PLAIN_JSON, +// JweAlgorithm.ECDH_ES, +// JweEncryption.A256GCM, +// ) +// +// val parsed = JWEObject.parse(encrypted) +// parsed.shouldNotBeNull() +// parsed.payload.shouldBeNull() +// +// parsed.decrypt(ECDHDecrypter(keyPair.private as ECPrivateKey)) +// parsed.payload.toString() shouldBe stringPayload +// } +// } +// } +// } +}) \ No newline at end of file