Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main'
Browse files Browse the repository at this point in the history
  • Loading branch information
waltkb committed Nov 22, 2023
2 parents 429e4c3 + 1fb3ef7 commit d097ca0
Show file tree
Hide file tree
Showing 48 changed files with 1,210 additions and 353 deletions.
1 change: 1 addition & 0 deletions waltid-crypto/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ kotlin {
val jvmTest by getting {
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
implementation("org.junit.jupiter:junit-jupiter-params:5.9.0")
}
}
publishing {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class TSEKey(
//private var publicKey: ByteArray? = null,
//override var keyType: KeyType? = null
private var _publicKey: ByteArray? = null, private var _keyType: KeyType? = null
) : id.walt.crypto.keys.Key() {
) : Key() {

@Transient
val retrievedKeyType by lazy { runBlocking { retrieveKeyType() } }
Expand Down Expand Up @@ -168,7 +168,7 @@ class TSEKey(
?: throwTSEError("No keys/1/public_key in data response")
).value

override suspend fun getPublicKey(): id.walt.crypto.keys.Key {
override suspend fun getPublicKey(): Key {
return LocalKey.importRawPublicKey(
type = keyType,
rawPublicKey = publicKey,
Expand Down Expand Up @@ -274,4 +274,4 @@ suspend fun main() {
println("Verified plaintext: ${verified.getOrNull()!!.decodeToString()}")

tseKey.delete()
}
}
139 changes: 106 additions & 33 deletions waltid-crypto/src/commonTest/kotlin/TSEKeyTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,44 +7,117 @@ import io.ktor.http.*
import io.ktor.util.*
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.condition.EnabledIf
import kotlin.test.Test
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.Assumptions.assumeTrue
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.Arguments
import org.junit.jupiter.params.provider.Arguments.arguments
import org.junit.jupiter.params.provider.MethodSource
import java.util.stream.Stream
import kotlin.streams.asStream
import kotlin.test.assertEquals
import kotlin.test.assertTrue

class TSEKeyTest {
private val payload = JsonObject(
mapOf(
"sub" to JsonPrimitive("16bb17e0-e733-4622-9384-122bc2fc6290"),
"iss" to JsonPrimitive("http://localhost:3000"),
"aud" to JsonPrimitive("TOKEN"),
)
)

fun getPublicKeyRepresentation() = runTest {

private suspend fun test(key: TSEKey) {
try {
println("TSEKey: $key")
val plaintext = "This is a plaintext for ${key.keyType.name}... 123".encodeToByteArray()
println("Plaintext: ${plaintext.decodeToString()}")

val signed = key.signRaw(plaintext) as String
println("Signed: $signed")

val verified = key.verifyRaw(signed.decodeBase64Bytes(), plaintext)
println("Verified signature success: ${verified.isSuccess}")
println("Verified plaintext: ${verified.getOrNull()!!.decodeToString()}")
} finally {
println("Deleting $key...")
key.delete()
}
}

@Test
@EnabledIf("hostCondition")
fun testAll() = runTest {
val tseMetadata = TSEKeyMetadata("http://127.0.0.1:8200/v1/transit", "dev-only-token")
@ParameterizedTest
@MethodSource
fun getPublicKey(key: TSEKey?) = runTest {
assumeTrue(hostCondition())
assumeTrue(key != null)
val publicKey = key!!.getPublicKey()
assertTrue(!publicKey.hasPrivateKey)
//TODO: assert keyId, thumbprint, export
}

fun getKeyType() = runTest {

}

fun getHasPrivateKey() = runTest {

}

@ParameterizedTest
@MethodSource
fun signRaw(key: TSEKey?) = runTest {
assumeTrue(hostCondition())
assumeTrue(key != null)
val signed = key!!.signRaw(payload.toString().encodeToByteArray()) as String
val verificationResult = key.verifyRaw(signed.decodeBase64Bytes(), payload.toString().encodeToByteArray())
assertTrue(verificationResult.isSuccess)
assertEquals(payload.toString(), String(verificationResult.getOrThrow()))
}

@ParameterizedTest
@MethodSource
fun signJws(key: TSEKey?) = runTest {
assumeTrue(hostCondition())
val signed = key!!.signJws(payload.toString().encodeToByteArray())
val verificationResult = key.verifyJws(signed)
assertTrue(verificationResult.isSuccess)
assertEquals(payload, verificationResult.getOrThrow())
}

fun getKeyId() = runTest {

}

fun verifyJws() = runTest {

}

fun exportJWK() = runTest {

}

fun exportJWKObject() = runTest {

listOf(
TSEKey.generate(KeyType.Ed25519, tseMetadata),
TSEKey.generate(KeyType.RSA, tseMetadata),
TSEKey.generate(KeyType.secp256r1, tseMetadata)
).forEach {
test(it)
}
}

private fun hostCondition() = runCatching {
runBlocking { HttpClient().get("http://127.0.0.1:8200") }.status == HttpStatusCode.OK
}.fold(onSuccess = { true }, onFailure = { false })
}
fun exportPEM() = runTest {

}

companion object {
private var keys: List<TSEKey?> = listOf(null)//ugly way to have test parameterization and condition at once

@JvmStatic
@BeforeAll
fun initKeys() = runTest {
hostCondition().takeIf { it }?.let {
val tseMetadata = TSEKeyMetadata("http://127.0.0.1:8200/v1/transit", "dev-only-token")
keys = enumValues<KeyType>().map { TSEKey.generate(KeyType.Ed25519, tseMetadata) }
}
}
@JvmStatic
@AfterAll
fun cleanup() = runTest {
keys.forEach { it?.delete() }
}
@JvmStatic
fun getPublicKey(): Stream<Arguments> = keys.map { arguments(it) }.asSequence().asStream()
@JvmStatic
fun signRaw(): Stream<Arguments> = keys.map { arguments(it) }.asSequence().asStream()
@JvmStatic
fun signJws(): Stream<Arguments> = keys.map { arguments(it) }.asSequence().asStream()

private fun hostCondition() = runCatching {
runBlocking { HttpClient().get("http://127.0.0.1:8200") }.status == HttpStatusCode.OK
}.fold(onSuccess = { it }, onFailure = { false })
}
}
92 changes: 92 additions & 0 deletions waltid-crypto/src/jvmTest/kotlin/ExportKeyTests.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import TestUtils.loadJwkLocal
import TestUtils.loadPemLocal
import TestUtils.loadSerializedLocal
import id.walt.crypto.keys.KeySerialization
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.Arguments
import org.junit.jupiter.params.provider.Arguments.arguments
import org.junit.jupiter.params.provider.MethodSource
import java.util.stream.Stream
import kotlin.test.assertEquals

class ExportKeyTests {

@ParameterizedTest
@MethodSource
fun `given key, when exporting jwk then the result is a valid jwk string`(keyFile: String, jwkFile: String) =
runTest {
// given
val key = KeySerialization.deserializeKey(keyFile).getOrThrow()
// when
val export = key.exportJWK()
// then
assertEquals(jwkFile.replace("\\s".toRegex(), ""), export)
}

@ParameterizedTest
@MethodSource
fun `given key, when exporting JsonObject then the result is a valid jwk string`(keyFile: String, jwkFile: String) = runTest {
// given
val key = KeySerialization.deserializeKey(keyFile).getOrThrow()
// when
val export = key.exportJWKObject()
// then
assertEquals(jwkFile.replace("\\s".toRegex(), ""), export.toString())
}

@ParameterizedTest
@MethodSource
@Disabled // not implemented
fun `given key, when exporting pem then the result is a valid pem string`(keyFile: String, pemFile: String) =
runTest {
// given
val key = KeySerialization.deserializeKey(keyFile).getOrThrow()
// when
val export = key.exportPEM()
// then
assertEquals(pemFile, export)
}

companion object {
@JvmStatic
fun `given key, when exporting jwk then the result is a valid jwk string`(): Stream<Arguments> = Stream.of(
arguments(loadSerializedLocal("ed25519.private.json"), loadJwkLocal("ed25519.private.json")),
arguments(loadSerializedLocal("secp256k1.private.json"), loadJwkLocal("secp256k1.private.json")),
arguments(loadSerializedLocal("secp256r1.private.json"), loadJwkLocal("secp256r1.private.json")),
arguments(loadSerializedLocal("rsa.private.json"), loadJwkLocal("rsa.private.json")),
// public
arguments(loadSerializedLocal("ed25519.public.json"), loadJwkLocal("ed25519.public.json")),
arguments(loadSerializedLocal("secp256k1.public.json"), loadJwkLocal("secp256k1.public.json")),
arguments(loadSerializedLocal("secp256r1.public.json"), loadJwkLocal("secp256r1.public.json")),
arguments(loadSerializedLocal("rsa.public.json"), loadJwkLocal("rsa.public.json")),
)

@JvmStatic
fun `given key, when exporting JsonObject then the result is a valid jwk string`(): Stream<Arguments> = Stream.of(
arguments(loadSerializedLocal("ed25519.private.json"), loadJwkLocal("ed25519.private.json")),
arguments(loadSerializedLocal("secp256k1.private.json"), loadJwkLocal("secp256k1.private.json")),
arguments(loadSerializedLocal("secp256r1.private.json"), loadJwkLocal("secp256r1.private.json")),
arguments(loadSerializedLocal("rsa.private.json"), loadJwkLocal("rsa.private.json")),
// public
arguments(loadSerializedLocal("ed25519.public.json"), loadJwkLocal("ed25519.public.json")),
arguments(loadSerializedLocal("secp256k1.public.json"), loadJwkLocal("secp256k1.public.json")),
arguments(loadSerializedLocal("secp256r1.public.json"), loadJwkLocal("secp256r1.public.json")),
arguments(loadSerializedLocal("rsa.public.json"), loadJwkLocal("rsa.public.json")),
)

@JvmStatic
fun `given key, when exporting pem then the result is a valid pem string`(): Stream<Arguments> = Stream.of(
arguments(loadSerializedLocal("ed25519.private.json"), loadPemLocal("ed25519.private.pem")),
arguments(loadSerializedLocal("secp256k1.private.json"), loadPemLocal("secp256k1.private.pem")),
arguments(loadSerializedLocal("secp256r1.private.json"), loadPemLocal("secp256r1.private.pem")),
arguments(loadSerializedLocal("rsa.private.json"), loadPemLocal("rsa.private.pem")),
// public
arguments(loadSerializedLocal("ed25519.public.json"), loadPemLocal("ed25519.public.pem")),
arguments(loadSerializedLocal("secp256k1.public.json"), loadPemLocal("secp256k1.public.pem")),
arguments(loadSerializedLocal("secp256r1.public.json"), loadPemLocal("secp256r1.public.pem")),
arguments(loadSerializedLocal("rsa.public.json"), loadPemLocal("rsa.public.pem")),
)
}
}
Loading

0 comments on commit d097ca0

Please sign in to comment.