a-sit-plus / signum

Kotlin Multiplatform Crypto/PKI Library and ASN1 Parser + Encoder
https://a-sit-plus.github.io/signum/
Apache License 2.0
76 stars 6 forks source link

Remove the generic restriction on the src parameter of the `verifyTag` function #144

Closed ShiinaSekiu closed 1 month ago

ShiinaSekiu commented 1 month ago

https://github.com/a-sit-plus/signum/blob/e8f9bd4a0be5a9018e6e4ffe137b22191b06c1e1/indispensable/src/commonMain/kotlin/at/asitplus/signum/indispensable/asn1/Asn1Encodable.kt#L99

In the following case, A is Asn1Structure. Therefore it cannot accept parameters of type Asn1Element or Asn1Primitive.

data class GetEuiccDataResponse(val eid : String) : Asn1Encodable<Asn1Structure>
{
    companion object : Asn1Decodable<Asn1Structure, GetEuiccDataResponse>
    {
        override fun doDecode(src : Asn1Structure) : GetEuiccDataResponse
        {
            val element = src.nextChild()
            verifyTag(element, Asn1.ImplicitTag(26U, TagClass.APPLICATION)) // error
            return GetEuiccDataResponse(element.asPrimitive().content.toHexString())
        }
    }

    override fun encodeToTlv() = throw NotImplementedError()
}

Or maybe verifyTag should be a separate tool? And not inside Asn1Decodable.

JesusMcCloud commented 1 month ago

Maybe the docs would benefit from better phrasing; the intention of veirfyTag, is to verify the tag of the AsnDecodable being decoded, not any of its child elements. In your case, it's purpose would be to verify the tag of GetEuiccDataResponse. You'd never directly invoke verifyTag, but rather, call GetEuiccDataResponse.decodeFromTlv(structure, getEUiccDataResponseTag). That is, if GetEuiccDataResponse is even tagged in a special way and requires tag verification.

Inside doDecode, if you want to verify the Tag of a child element, you'll want to try something along the lines of the following (assuming, the structure is always a toplevel structure with a single hex string primitive):

return GetEuiccDataResponse(
    src.nextChild().asPrimitive().decode(
        Asn1.ImplicitTag(26U, TagClass.APPLICATION)
    ) { it.toHexString() }
)
ShiinaSekiu commented 1 month ago

Thanks, I understand. I'll close this issue.

ShiinaSekiu commented 1 month ago

Is there a more simplified way to write this?

            val euiccCiPKIdListForVerification = src.nextChild().let {
                val expected = Asn1.ExplicitTag(9U)
                if (it.tag != expected) throw Asn1TagMismatchException(expected, it.tag)
                it.asStructure().children.filterIsInstance<Asn1Primitive>().map { it.content.toHexString() }
            }
JesusMcCloud commented 1 month ago

actually not. but an after-the-fact tag verification will be added to Asn1Element for the next release. The issue is here: #149 . In the meantime, you can add it as an extension in your local codebase, until the next release is shipped.

ShiinaSekiu commented 1 month ago

Is there any way to simplify this by implementing Asn1Decodable? Asn1Primitive Asn1BitString -> List<Enum>

enum class PprIds(val bitPosition : Long)
{
    PPR_UPDATE_CONTROL(0),
    PPR1(1),
    PPR2(2);

    companion object
    {
        @Throws(Asn1Exception::class)
        fun decodeFromTlv(src : Asn1Primitive, assertTag : Asn1Element.Tag? = null) : List<PprIds> {
            verifyTag(src, assertTag)
            return doDecode(src)
        }

        @Throws(Asn1TagMismatchException::class)
        fun verifyTag(src : Asn1Primitive, assertTag : Asn1Element.Tag?) {
            val expected = assertTag ?: return
            if (src.tag != expected)
                throw Asn1TagMismatchException(expected, src.tag)
        }

        fun doDecode(src : Asn1Primitive) : List<PprIds>
        {
            val bitSet = Asn1BitString.doDecode(src).toBitSet()
            return PprIds.entries.filter { bitSet[it.bitPosition] }
        }
    }
}
JesusMcCloud commented 1 month ago

unless i'm missing somehting it is enough to override doDecode(). everything else has default implementations

JesusMcCloud commented 1 month ago

(see also: https://a-sit-plus.github.io/signum/indispensable/#high-level)

ShiinaSekiu commented 1 month ago

unless i'm missing somehting it is enough to override . everything else has default implementationsdoDecode()

No, what I want is that doDecode should return List<PprIds>. But if I implement Asn1Decodable it only can returns PprIds.

JesusMcCloud commented 1 month ago

I'm probably still missing something, but how about having something implement Asn1Decodable<List<PprIds>>? then your're down to implementing doDecode()