Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Release 1.1.2 #10

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[![Powered by VC-K](https://img.shields.io/badge/VC--K-powered-8A2BE2?logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA4LjAzIDkuNSI+PGcgZmlsbD0iIzhhMmJlMiIgZm9udC1mYW1pbHk9IlZBTE9SQU5UIiBmb250LXNpemU9IjEyLjciIHRleHQtYW5jaG9yPSJtaWRkbGUiPjxwYXRoIGQ9Ik01OS42NCAyMjIuMTNxMC0uOTguMzYtMS44Mi4zNy0uODQuOTgtMS40Ni42Mi0uNjIgMS40Ni0uOTYuODMtLjM2IDEuOC0uMzUgMS4wMy4wMiAxLjkuNDIuODcuNCAxLjUgMS4xMi4wNC4wNS4wMy4xMSAwIC4wNy0uMDUuMWwtMSAuODZxLS4wNi4wMy0uMTIuMDN0LS4xLS4wNnEtLjQyLS40OC0xLS43Ni0uNTYtLjMtMS4yMi0uMjgtLjYuMDEtMS4xMy4yNy0uNTQuMjQtLjkzLjY3LS40LjQyLS42Mi45OC0uMjMuNTYtLjIzIDEuMiAwIC42My4yNCAxLjE4LjI0LjU2LjY1Ljk4LjQuNDIuOTQuNjYuNTMuMjMgMS4xNC4yMy42My0uMDEgMS4yLS4zLjU1LS4yNy45Ni0uNzUuMDQtLjA1LjEtLjA1LjA2LS4wMi4xMS4wM2wxIC44NnEuMDYuMDMuMDYuMS4wMS4wNi0uMDMuMTEtLjY0LjczLTEuNTMgMS4xNC0uOS40MS0xLjk1LjQtLjk1IDAtMS43OS0uMzYtLjgyLS4zNy0xLjQzLS45OS0uNjEtLjYzLS45NS0xLjQ4LS4zNS0uODUtLjM1LTEuODN6IiBzdHlsZT0iLWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjpWQUxPUkFOVDt0ZXh0LWFsaWduOmNlbnRlciIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTU5LjY0IC0yMTcuNDIpIi8+PHBhdGggZD0iTTY2LjIxIDIyMS4zNWgxLjNjLjEgMCAuMTYuMDYuMTYuMTd2MS4zOGMwIC4xMS0uMDUuMTctLjE2LjE3aC0xLjNjLS4xIDAtLjE2LS4wNi0uMTYtLjE3di0xLjM4YzAtLjExLjA1LS4xNy4xNi0uMTd6IiBsZXR0ZXItc3BhY2luZz0iLTMuMTIiIHN0eWxlPSItaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOlZBTE9SQU5UO3RleHQtYWxpZ246Y2VudGVyIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtNTkuNjQgLTIxNy40MikiLz48L2c+PC9zdmc+&logoColor=white&labelColor=white)](https://github.com/a-sit-plus/vck)
[![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-brightgreen.svg?style=flat)](http://www.apache.org/licenses/LICENSE-2.0)
[![Kotlin](https://img.shields.io/badge/kotlin-multiplatform--mobile-orange.svg?logo=kotlin)](http://kotlinlang.org)
[![Kotlin](https://img.shields.io/badge/kotlin-2.0.20-blue.svg?logo=kotlin)](http://kotlinlang.org)
[![Kotlin](https://img.shields.io/badge/kotlin-2.1.0-blue.svg?logo=kotlin)](http://kotlinlang.org)
![Java](https://img.shields.io/badge/java-17-blue.svg?logo=OPENJDK)
[![Maven Central](https://img.shields.io/maven-central/v/at.asitplus.wallet/mobiledrivinglicence)](https://mvnrepository.com/artifact/at.asitplus.wallet/mobiledrivinglicence/)

Expand Down Expand Up @@ -50,6 +50,10 @@ These attributes are implemented:

## Changelog

Release 1.1.2
- VC-K 5.2.1
- Kotlin 2.1.0

Release 1.1.1:
- Fix serialization of boolean element `age_over_18`

Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
id("at.asitplus.gradle.conventions") version "2.0.20+20240920"
id("at.asitplus.gradle.conventions") version "2.1.0+20241219"
}

val artifactVersion: String by extra
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ kotlin.mpp.enableCInteropCommonization=true
kotlin.mpp.stability.nowarn=true
kotlin.native.ignoreDisabledTargets=true

artifactVersion = 1.1.1
artifactVersion = 1.1.2
jdk.version=17
2 changes: 1 addition & 1 deletion mobiledrivinglicence/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ kotlin {
sourceSets {
commonMain {
dependencies {
api("at.asitplus.wallet:vck:5.0.0")
api("at.asitplus.wallet:vck:5.2.1")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import io.matthewnelson.encoding.core.Decoder.Companion.decodeToByteArray
import io.matthewnelson.encoding.core.Encoder.Companion.encodeToString
import kotlinx.datetime.Instant
import kotlinx.datetime.LocalDate
import kotlinx.serialization.builtins.ByteArraySerializer
import kotlin.random.Random

class CborSerializationTest : FreeSpec({
Expand Down Expand Up @@ -320,7 +321,7 @@ class CborSerializationTest : FreeSpec({
issueDate = LocalDate.parse("2017-02-23"),
expiryDate = LocalDate.parse("2024-10-20")
)
val mso = document.issuerSigned.getIssuerAuthPayloadAsMso().getOrThrow()
val mso = document.issuerSigned.issuerAuth.payload!!

mso.version shouldBe "1.0"
mso.digestAlgorithm shouldBe "SHA-256"
Expand Down Expand Up @@ -383,7 +384,7 @@ class CborSerializationTest : FreeSpec({
""".trimIndent().replace("\n", "").uppercase()

val inputDecoded = input.decodeToByteArray(Base16(true))
val deserialized = IssuerSignedItem.deserialize(inputDecoded, MobileDrivingLicenceScheme.isoNamespace)
val deserialized = IssuerSignedItem.deserialize(inputDecoded, MobileDrivingLicenceScheme.isoNamespace, elementIdentifier = "issue_date")
.getOrThrow().shouldNotBeNull()
val serialized = deserialized.serialize(MobileDrivingLicenceScheme.isoNamespace)

Expand Down Expand Up @@ -447,7 +448,7 @@ class CborSerializationTest : FreeSpec({
""".trimIndent().replace("\n", "")

val inputDecoded = input.decodeToByteArray(Base16(true))
val deserialized = IssuerSignedItem.deserialize(inputDecoded, MobileDrivingLicenceScheme.isoNamespace)
val deserialized = IssuerSignedItem.deserialize(inputDecoded, MobileDrivingLicenceScheme.isoNamespace, elementIdentifier = "driving_privileges")
.getOrThrow().shouldNotBeNull()
val serialized = deserialized.serialize(MobileDrivingLicenceScheme.isoNamespace)

Expand Down Expand Up @@ -564,11 +565,10 @@ class CborSerializationTest : FreeSpec({
044b890ad85aa53f129134775d733754d7cb7a413766aeff13cb2e
""".trimIndent().replace("\n", "").uppercase()

val coseSigned = CoseSigned.deserialize(input.decodeToByteArray(Base16(true))).getOrThrow()
val coseSigned = CoseSigned.deserialize(MobileSecurityObject.serializer(), input.decodeToByteArray(Base16(true))).getOrThrow()

val payload = coseSigned.payload
payload.shouldNotBeNull()
val mso = MobileSecurityObject.deserializeFromIssuerAuth(payload).getOrThrow().shouldNotBeNull()

val mso = coseSigned.payload!!
mso.version shouldBe "1.0"
mso.digestAlgorithm shouldBe "SHA-256"
mso.docType shouldBe MobileDrivingLicenceScheme.isoDocType
Expand All @@ -588,7 +588,7 @@ class CborSerializationTest : FreeSpec({
valueDigestListUs.findItem(1U) shouldBe "4D80E1E2E4FB246D97895427CE7000BB59BB24C8CD003ECF94BF35BBD2917E34"
.decodeToByteArray(Base16(true))

coseSigned.serialize().encodeToString(Base16(true)) shouldBe input
coseSigned.serialize(MobileSecurityObject.serializer()).encodeToString(Base16(true)) shouldBe input
}

})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import io.matthewnelson.encoding.base16.Base16
import io.matthewnelson.encoding.core.Encoder.Companion.encodeToString
import kotlinx.datetime.Clock
import kotlinx.datetime.LocalDate
import kotlinx.serialization.builtins.ByteArraySerializer
import kotlin.random.Random

class IsoMdocTest : FreeSpec({
Expand Down Expand Up @@ -55,7 +56,7 @@ class Wallet {
)

var storedMdl: MobileDrivingLicence? = null
var storedIssuerAuth: CoseSigned? = null
var storedIssuerAuth: CoseSigned<MobileSecurityObject>? = null
var storedMdlItems: IssuerSignedList? = null

fun storeMdl(deviceResponse: DeviceResponse) {
Expand All @@ -65,7 +66,7 @@ class Wallet {
this.storedIssuerAuth = issuerAuth

issuerAuth.payload.shouldNotBeNull()
val mso = document.issuerSigned.getIssuerAuthPayloadAsMso().getOrThrow()
val mso = document.issuerSigned.issuerAuth.payload!!

val mdlItems = document.issuerSigned.namespaces?.get(MobileDrivingLicenceScheme.isoNamespace).shouldNotBeNull()
this.storedMdlItems = mdlItems
Expand Down Expand Up @@ -93,6 +94,7 @@ class Wallet {
val itemsRequest = verifierRequest.docRequests[0].itemsRequest
val isoNamespace = itemsRequest.value.namespaces[MobileDrivingLicenceScheme.isoNamespace].shouldNotBeNull()
val requestedKeys = isoNamespace.entries.filter { it.value }.map { it.key }

return DeviceResponse(
version = "1.0",
documents = arrayOf(
Expand All @@ -110,8 +112,11 @@ class Wallet {
namespaces = ByteStringWrapper(DeviceNameSpaces(mapOf())),
deviceAuth = DeviceAuth(
deviceSignature = coseService.createSignedCose(
payload = null,
addKeyId = false
protectedHeader = null,
payload = byteArrayOf(),
serializer = ByteArraySerializer(),
addKeyId = false,
addCertificate = false,
).getOrThrow()
)
)
Expand Down Expand Up @@ -173,7 +178,8 @@ class Issuer {
MobileDrivingLicenceScheme.isoNamespace to issuerSigned
),
issuerAuth = coseService.createSignedCose(
payload = mso.serializeForIssuerAuth(),
payload = mso,
serializer = MobileSecurityObject.serializer(),
addKeyId = false,
addCertificate = true,
).getOrThrow()
Expand Down Expand Up @@ -215,7 +221,8 @@ class Verifier {
),
readerAuth = coseService.createSignedCose(
unprotectedHeader = CoseHeader(),
payload = null,
payload = byteArrayOf(),
serializer = ByteArraySerializer(),
addKeyId = false,
).getOrThrow()
)
Expand All @@ -231,7 +238,7 @@ class Verifier {
val issuerAuth = issuerSigned.issuerAuth
verifierCoseService.verifyCose(issuerAuth, issuerKey).isSuccess shouldBe true
issuerAuth.payload.shouldNotBeNull()
val mso = issuerSigned.getIssuerAuthPayloadAsMso().getOrThrow()
val mso = issuerSigned.issuerAuth.payload!!

mso.docType shouldBe MobileDrivingLicenceScheme.isoDocType
val mdlItems = mso.valueDigests[MobileDrivingLicenceScheme.isoNamespace].shouldNotBeNull()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
package at.asitplus.wallet.mdl

import at.asitplus.signum.indispensable.CryptoSignature
import at.asitplus.signum.indispensable.cosef.CoseEllipticCurve
import at.asitplus.signum.indispensable.cosef.CoseHeader
import at.asitplus.signum.indispensable.cosef.CoseKey
import at.asitplus.signum.indispensable.cosef.CoseKeyParams
import at.asitplus.signum.indispensable.cosef.CoseKeyType
import at.asitplus.signum.indispensable.cosef.CoseSigned
import at.asitplus.signum.indispensable.cosef.io.ByteStringWrapper
import at.asitplus.wallet.lib.agent.SubjectCredentialStore
import at.asitplus.wallet.lib.data.CredentialToJsonConverter
import at.asitplus.wallet.lib.iso.DeviceKeyInfo
import at.asitplus.wallet.lib.iso.IssuerSigned
import at.asitplus.wallet.lib.iso.IssuerSignedItem
import at.asitplus.wallet.lib.iso.MobileSecurityObject
import at.asitplus.wallet.lib.iso.ValidityInfo
import at.asitplus.wallet.lib.iso.ValueDigest
import at.asitplus.wallet.lib.iso.ValueDigestList
import at.asitplus.wallet.mdl.MobileDrivingLicenceDataElements.ADMINISTRATIVE_NUMBER
import at.asitplus.wallet.mdl.MobileDrivingLicenceDataElements.AGE_BIRTH_YEAR
import at.asitplus.wallet.mdl.MobileDrivingLicenceDataElements.AGE_IN_YEARS
Expand Down Expand Up @@ -47,7 +57,9 @@ import io.kotest.matchers.shouldBe
import io.kotest.matchers.types.shouldBeInstanceOf
import io.matthewnelson.encoding.base64.Base64
import io.matthewnelson.encoding.core.Encoder.Companion.encodeToString
import kotlinx.datetime.Clock
import kotlinx.datetime.LocalDate
import kotlinx.serialization.builtins.ByteArraySerializer
import kotlinx.serialization.json.JsonObject
import kotlin.random.Random
import kotlin.random.nextUInt
Expand All @@ -57,23 +69,36 @@ class SerializerRegistrationTest : FreeSpec({
"Serialization and deserialization" - {
withData(nameFn = { " for ${it.key}" }, dataMap().entries) {

val serialized = it.toIssuerSignedItem().serialize(MobileDrivingLicenceScheme.isoNamespace)
val item = it.toIssuerSignedItem()
val serialized = item.serialize(MobileDrivingLicenceScheme.isoNamespace)

val deserialized = IssuerSignedItem.deserialize(serialized, MobileDrivingLicenceScheme.isoNamespace)
val deserialized = IssuerSignedItem.deserialize(serialized, MobileDrivingLicenceScheme.isoNamespace,item.elementIdentifier)
.getOrThrow()

deserialized.elementValue shouldBe it.value
}
}

"Serialization to JSON Element" {

val mso = MobileSecurityObject(
version = "1.0",
digestAlgorithm = "SHA-256",
valueDigests = mapOf("foo" to ValueDigestList(listOf(ValueDigest(0U, byteArrayOf())))),
deviceKeyInfo = deviceKeyInfo(),
docType = "docType",
validityInfo = ValidityInfo(Clock.System.now(), Clock.System.now(), Clock.System.now())
)

val claims = dataMap()
val namespacedItems: Map<String, List<IssuerSignedItem>> =
mapOf(MobileDrivingLicenceScheme.isoNamespace to claims.map { it.toIssuerSignedItem() }.toList())
val issuerAuth = CoseSigned(ByteStringWrapper(CoseHeader()), null, null, byteArrayOf())
val issuerAuth = CoseSigned.create(CoseHeader(),null, mso, CryptoSignature.RSAorHMAC(byteArrayOf(1,3,3,7)),
MobileSecurityObject.serializer()
)
val credential = SubjectCredentialStore.StoreEntry.Iso(
IssuerSigned.fromIssuerSignedItems(namespacedItems, issuerAuth),
MobileDrivingLicenceScheme
MobileDrivingLicenceScheme.isoNamespace
)
val converted = CredentialToJsonConverter.toJsonElement(credential)
.shouldBeInstanceOf<JsonObject>()
Expand Down Expand Up @@ -137,3 +162,7 @@ private fun dataMap(): Map<String, Any> =
private fun randomString() = Random.nextBytes(16).encodeToString(Base64())

private fun randomLocalDate() = LocalDate(Random.nextInt(1900, 2100), Random.nextInt(1, 12), Random.nextInt(1, 28))


private fun deviceKeyInfo() =
DeviceKeyInfo(CoseKey(CoseKeyType.EC2, keyParams = CoseKeyParams.EcYBoolParams(CoseEllipticCurve.P256)))
20 changes: 20 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,25 @@ pluginManagement {
}
}

if (System.getProperty("regressionTest") == "true") {
includeBuild("../signum") {
dependencySubstitution {
substitute(module("at.asitplus.wallet:indispensable")).using(project(":indispensable"))
substitute(module("at.asitplus.signum:indispensable-josef")).using(project(":indispensable-josef"))
substitute(module("at.asitplus.signum:indispensable-cosef")).using(project(":indispensable-cosef"))
substitute(module("at.asitplus.signum:supreme")).using(project(":supreme"))
}
}
includeBuild("..") {
dependencySubstitution {
substitute(module("at.asitplus.wallet:vck")).using(project(":vck"))
substitute(module("at.asitplus.wallet:vck-openid")).using(project(":vck-openid"))
substitute(module("at.asitplus.wallet:vck-openid-ktor")).using(project(":vck-openid-ktor"))
substitute(module("at.asitplus.wallet:openid-data-classes")).using(project(":openid-data-classes"))
}
}
}


rootProject.name = "mobile-driving-licence"
include(":mobiledrivinglicence")
Loading