Skip to content

Commit

Permalink
Clarify tagging ISO structures with tag 24
Browse files Browse the repository at this point in the history
  • Loading branch information
nodh committed Sep 25, 2024
1 parent ef9f971 commit 10a189d
Show file tree
Hide file tree
Showing 10 changed files with 310 additions and 41 deletions.
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ include(":openid-data-classes")
include(":vck")
include(":vck-aries")
include(":vck-openid")
include(":mobiledrivinglicence")

dependencyResolutionManagement {
repositories {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,14 +145,13 @@ class IssuerAgent(
validUntil = expirationDate,
)
)
val issuerSigned = IssuerSigned(
val issuerSigned = IssuerSigned.fromIssuerSignedItems(
namespacedItems = mapOf(scheme.isoNamespace!! to credential.issuerSignedItems),
issuerAuth = coseService.createSignedCose(
payload = mso.serializeForIssuerAuth(),
addKeyId = false,
addCertificate = true,
).getOrThrow(),
24 // TODO verify serialization of this
)
return Issuer.IssuedCredential.Iso(issuerSigned, scheme)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package at.asitplus.wallet.lib.agent

import at.asitplus.signum.indispensable.CryptoPublicKey
import at.asitplus.signum.indispensable.cosef.CoseKey
import at.asitplus.signum.indispensable.cosef.io.ByteStringWrapper
import at.asitplus.signum.indispensable.cosef.toCoseKey
import at.asitplus.signum.indispensable.equalsCryptographically
import at.asitplus.signum.indispensable.io.Base64Strict
Expand All @@ -23,7 +24,6 @@ import io.github.aakira.napier.Napier
import io.matthewnelson.encoding.base16.Base16
import io.matthewnelson.encoding.core.Decoder.Companion.decodeToByteArrayOrNull
import io.matthewnelson.encoding.core.Encoder.Companion.encodeToString
import at.asitplus.signum.indispensable.cosef.io.ByteStringWrapper


/**
Expand Down Expand Up @@ -262,7 +262,7 @@ class Validator(
.also { Napier.w("IssuerAuth not verified: $issuerAuth") }
}

val mso = issuerSigned.getIssuerAuthPayloadAsMso()
val mso = issuerSigned.getIssuerAuthPayloadAsMso().getOrNull()
?: return Verifier.VerifyPresentationResult.InvalidStructure(docSerialized)
.also { Napier.w("MSO is null: ${issuerAuth.payload?.encodeToString(Base16(strict = true))}") }
if (mso.docType != doc.docType) {
Expand Down Expand Up @@ -304,12 +304,10 @@ class Validator(
}

private fun ByteStringWrapper<IssuerSignedItem>.verify(mdlItems: ValueDigestList?): Boolean {
val issuerHash = mdlItems?.entries?.firstOrNull { it.key == value.digestId } ?: return false
// TODO analyze usages of tag wrapping
val issuerHash = mdlItems?.entries?.firstOrNull { it.key == value.digestId }
?: return false
val verifierHash = serialized.wrapInCborTag(24).sha256()
if (!verifierHash.encodeToString(Base16(strict = true))
.contentEquals(issuerHash.value.encodeToString(Base16(strict = true)))
) {
if (!verifierHash.contentEquals(issuerHash.value)) {
Napier.w("Could not verify hash of value for ${value.elementIdentifier}")
return false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ class VerifiablePresentationFactory(
return Holder.CreatePresentationResult.Document(
Document(
docType = credential.scheme.isoDocType!!,
issuerSigned = IssuerSigned(
issuerSigned = IssuerSigned.fromIssuerSignedItems(
namespacedItems = disclosedItems,
issuerAuth = credential.issuerSigned.issuerAuth
),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package at.asitplus.wallet.lib.iso

import at.asitplus.KmmResult.Companion.wrap
import at.asitplus.catching
import at.asitplus.signum.indispensable.cosef.CoseSigned
import at.asitplus.signum.indispensable.cosef.io.ByteStringWrapper
import at.asitplus.signum.indispensable.cosef.io.ByteStringWrapperSerializer
import kotlinx.serialization.*

/**
Expand All @@ -17,25 +17,8 @@ data class IssuerSigned private constructor(
@SerialName("issuerAuth")
val issuerAuth: CoseSigned,
) {

constructor(
namespacedItems: Map<String, List<IssuerSignedItem>>,
issuerAuth: CoseSigned,
tag: Byte? = null
) : this(
issuerAuth = issuerAuth,
namespaces = namespacedItems.map { (ns, value) ->
ns to IssuerSignedList(
value.map { item ->
ByteStringWrapper(
item,
item.serialize(ns).let { tag?.let { tg -> it.wrapInCborTag(tg) } ?: it })
})
}.toMap()
)

fun getIssuerAuthPayloadAsMso() = issuerAuth.payload?.stripCborTag(24)?.let {
vckCborSerializer.decodeFromByteArray(ByteStringWrapperSerializer(MobileSecurityObject.serializer()), it).value
fun getIssuerAuthPayloadAsMso() = catching {
MobileSecurityObject.deserializeFromIssuerAuth(issuerAuth.payload!!).getOrThrow()
}

fun serialize() = vckCborSerializer.encodeToByteArray(this)
Expand All @@ -59,5 +42,19 @@ data class IssuerSigned private constructor(
fun deserialize(it: ByteArray) = kotlin.runCatching {
vckCborSerializer.decodeFromByteArray<IssuerSigned>(it)
}.wrap()

// Note: Can't be a secondary constructor, because it would have the same JVM signature as the primary one.
fun fromIssuerSignedItems(
namespacedItems: Map<String, List<IssuerSignedItem>>,
issuerAuth: CoseSigned
): IssuerSigned = IssuerSigned(
issuerAuth = issuerAuth,
namespaces = namespacedItems.map { (namespace, value) ->
namespace to IssuerSignedList(value.map { item ->
ByteStringWrapper(item, item.serialize(namespace).wrapInCborTag(24))
})
}.toMap()
)

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ data class MobileSecurityObject(
fun serialize() = vckCborSerializer.encodeToByteArray(this)

fun serializeForIssuerAuth() = vckCborSerializer.encodeToByteArray(
ByteStringWrapperSerializer<MobileSecurityObject>(serializer()), ByteStringWrapper(this)
ByteStringWrapperSerializer(serializer()), ByteStringWrapper(this)
).wrapInCborTag(24)

companion object {
fun deserializeFromIssuerAuth(it: ByteArray) = kotlin.runCatching {
vckCborSerializer.decodeFromByteArray(
ByteStringWrapperSerializer<MobileSecurityObject>(serializer()),
ByteStringWrapperSerializer(serializer()),
it.stripCborTag(24)
).value
}.wrap()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,14 @@ val vckCborSerializer by lazy {
}


fun ByteArray.stripCborTag(tag: Byte) = this.dropWhile { it == 0xd8.toByte() }.dropWhile { it == tag }.toByteArray()
fun ByteArray.stripCborTag(tag: Byte): ByteArray {
val tagBytes = byteArrayOf(0xd8.toByte(), tag)
return if (this.take(tagBytes.size).toByteArray().contentEquals(tagBytes)) {
this.drop(tagBytes.size).toByteArray()
} else {
this
}
}

fun ByteArray.wrapInCborTag(tag: Byte) = byteArrayOf(0xd8.toByte()) + byteArrayOf(tag) + this

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class IssuerSignedItemSerializationTest : FreeSpec({
val issuerAuth = CoseSigned(protectedHeader, null, null, byteArrayOf())
val doc = Document(
docType = uuid4().toString(),
issuerSigned = IssuerSigned(
issuerSigned = IssuerSigned.fromIssuerSignedItems(
mapOf(namespace to listOf(item)),
issuerAuth
),
Expand Down
Loading

0 comments on commit 10a189d

Please sign in to comment.