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/3.8.0 #132

Merged
merged 8 commits into from
Sep 20, 2024
Merged
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
44 changes: 44 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,51 @@
# Changelog


## 3.0

### 3.8.0 (Supreme 0.3.0) Breaking Changes Ahead!
* Completely revamped ASN.1 Tag Handling
* Properly handle multi-byte tags
* Introduce a new data structure `TLV.Tag` with an accompanying `TagClass` enum and a `constructed` flag to accurately represent arbitrary tags up to `ULong.MAX_VALUE`
* Make all `tag` parameters `ULong` to reflect support for multi-byte tags
* Remove `DERTags`
* Revamp implicit tagging (there is still work to be done, but at least it supports CONSTRUCTED ASN.1 elements)
* Refactor `Int.Companion.decodeFromDer` -> `Int.Companion.decodeFromDerValue()`
* Refactor `Long.Companion.decodeFromDer` -> `Long.Companion.decodeFromDerValue()`
* Introduce `ULong.Companion.decodeFromDer` which can handle overlong inputs, as long as they start with a valid ULong encoding
* Changed return type of `Verifier::verify` from `KmmResult<Unit>` to `KmmResult<Success>`. Usage is unchanged.
* Add `ConfirmationClaim` to represent [Proof-of-Possesion Key Semantics for JWTs](https://datatracker.ietf.org/doc/html/rfc7800)
* Add claims to `JsonWebToken` to implement [Demonstrating Proof of Possession](https://datatracker.ietf.org/doc/html/rfc9449)
* Replace `JsonWebToken.confirmationKey` by `JsonWebToken.confirmationClaim`, the implementation was wrong
* Introduce `ULong.toAsn1VarInt()` to encode ULongs into ASN.1 unsigned VarInts (**not to be confused with
multi^2_base's`UVarInt`!**)
* Introduce `decodeAsn1VarULong()` and `decodeAsn1VarUInt()` which can handle overlong inputs, as long as they start with a valid unsigned number encoding.
* Comes in three ULong flavours:
* `Iterator<Byte>.decodeAsn1VarULong()`
* `Iterable<Byte>.decodeAsn1VarULong()`
* `ByteArray.decodeAsn1VarULong()`
* and three UInt flavours:
* `Iterator<Byte>.decodeAsn1VarUInt()`
* `Iterable<Byte>.decodeAsn1VarUInt()`
* `ByteArray.decodeAsn1VarUInt()`
* Revamp implicit tagging
* Revamp `Asn1Element.parse()`, introducing new variants. This yields:
* `Asn1Element.parse()` with the same semantics as before
* `Asn1Element.parse()` alternative introduced, which takes a `ByteIterator` instead of a `ByteArray`
* `Asn1Element.parseAll()` introduced, which consumes all bytes and returns a list of all ASN.1 elements (if parsing works)
* Variant 1 takes a `ByteIterator`
* Variant 2 takes a `ByteArray`
* `Asn1Element.parseFirst()` introduced, which tries to only parse a single ASN.1 element from the input and leaves the rest untouched.
* Variant 1 takes a `ByteIterator` and returns the element; the `ByteIterator` is advanced accordingly
* Variant 2 takes a `ByteArray` and returns a `Pair` of `(element, remainingBytes)`
* More consistent low-level encoding and decoding function names:
* `encodeToAsn1Primitive` to produce an `Asn1Primitive` that can directly be DER-encoded
* `encodeToAsn1ContentBytes` to produce the content bytes of a TLV primitive (the _V_ in TLV)
* `decodeToXXX` to be invoked on an `Asn1Primitive` to decode a DER-encoded primitive into the target type
* `decodeFromAsn1ContentBytes` to be invoked on the companion of the target type to decode the content bytes of a TLV primitive (the _V_ in TLV)
* Update conventions -> Coroutines 1.0.9
* replace `runCatching` with `catching` to be extra-safe

### 3.7.0 (Supreme 0.2.0)
* Remove Swift verifier logic to obtain a general speed-up
* Implement supreme signing capabilities
Expand Down
189 changes: 113 additions & 76 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@
[![A-SIT Plus Official](https://img.shields.io/badge/A--SIT_Plus-official-005b79?logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNDMuNzYyODYgMTg0LjgxOTk5Ij48ZGVmcz48Y2xpcFBhdGggaWQ9ImEiIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aCBkPSJNMCA1OTUuMjhoODQxLjg5VjBIMFoiLz48L2NsaXBQYXRoPjwvZGVmcz48ZyBjbGlwLXBhdGg9InVybCgjYSkiIHRyYW5zZm9ybT0ibWF0cml4KDEuMzMzMzMzMyAwIDAgLTEuMzMzMzMzMyAtNDgyLjI1IDUxNy41MykiPjxwYXRoIGZpbGw9IiMwMDViNzkiIGQ9Ik00MTUuNjcgMjQ5LjUzYy03LjE1LjA4LTEzLjk0IDEtMjAuMTcgMi43NWE1Mi4zMyA1Mi4zMyAwIDAgMC0xNy40OCA4LjQ2IDQwLjQzIDQwLjQzIDAgMCAwLTExLjk2IDE0LjU2Yy0yLjY4IDUuNDEtNC4xNCAxMS44NC00LjM1IDE5LjA5bC0uMDIgNi4xMnYyLjE3YS43MS43MSAwIDAgMCAuNy43M2gxNi41MmMuMzkgMCAuNy0uMzIuNzEtLjdsLjAxLTIuMmMwLTIuNi4wMi01LjgyLjAzLTYuMDcuMi00LjYgMS4yNC04LjY2IDMuMDgtMTIuMDZhMjguNTIgMjguNTIgMCAwIDEgOC4yMy05LjU4IDM1LjI1IDM1LjI1IDAgMCAxIDExLjk2LTUuNTggNTUuMzggNTUuMzggMCAwIDEgMTIuNTgtMS43NmM0LjMyLjEgOC42LjcgMTIuNzQgMS44YTM1LjA3IDM1LjA3IDAgMCAxIDExLjk2IDUuNTcgMjguNTQgMjguNTQgMCAwIDEgOC4yNCA5LjU3YzEuOTYgMy42NCAzIDguMDIgMy4xMiAxMy4wMnYyNC4wOUgzNjIuNGEuNy43IDAgMCAwLS43MS43VjMzNWMwIDguNDMuMDEgOC4wNS4wMSA4LjE0LjIgNy4zIDEuNjcgMTMuNzcgNC4zNiAxOS4yMmE0MC40MyA0MC40MyAwIDAgMCAxMS45NiAxNC41N2M1IDMuNzYgMTAuODcgNi42MSAxNy40OCA4LjQ2YTc3LjUgNzcuNSAwIDAgMCAyMC4wMiAyLjc3YzcuMTUtLjA3IDEzLjk0LTEgMjAuMTctMi43NGE1Mi4zIDUyLjMgMCAwIDAgMTcuNDgtOC40NiA0MC40IDQwLjQgMCAwIDAgMTEuOTUtMTQuNTdjMS42Mi0zLjI2IDMuNzctMTAuMDQgMy43Ny0xNC42OCAwLS4zOC0uMTctLjc0LS41NC0uODJsLTE2Ljg5LS40Yy0uMi0uMDQtLjM0LjM0LS4zNC41NCAwIC4yNy0uMDMuNC0uMDYuNi0uNSAyLjgyLTEuMzggNS40LTIuNjEgNy42OWEyOC41MyAyOC41MyAwIDAgMS04LjI0IDkuNTggMzUuMDEgMzUuMDEgMCAwIDEtMTEuOTYgNS41NyA1NS4yNSA1NS4yNSAwIDAgMS0xMi41NyAxLjc3Yy00LjMyLS4xLTguNjEtLjcxLTEyLjc1LTEuOGEzNS4wNSAzNS4wNSAwIDAgMS0xMS45Ni01LjU3IDI4LjUyIDI4LjUyIDAgMCAxLTguMjMtOS41OGMtMS44Ni0zLjQ0LTIuOS03LjU1LTMuMDktMTIuMmwtLjAxLTcuNDdoODkuMTZhLjcuNyAwIDAgMCAuNy0uNzJ2LTM5LjVjLS4xLTcuNjUtMS41OC0xNC40LTQuMzgtMjAuMDZhNDAuNCA0MC40IDAgMCAwLTExLjk1LTE0LjU2IDUyLjM3IDUyLjM3IDAgMCAwLTE3LjQ4LTguNDcgNzcuNTYgNzcuNTYgMCAwIDAtMjAuMDEtMi43N1oiLz48cGF0aCBmaWxsPSIjY2U0OTJlIiBkPSJNNDE5LjM4IDI4MC42M2gtNy41N2EuNy43IDAgMCAwLS43MS43MXYxNS40MmE4LjE3IDguMTcgMCAwIDAtMy43OCA2LjkgOC4yOCA4LjI4IDAgMCAwIDE2LjU0IDAgOC4yOSA4LjI5IDAgMCAwLTMuNzYtNi45di0xNS40MmEuNy43IDAgMCAwLS43Mi0uNzEiLz48L2c%2BPC9zdmc%2B&logoColor=white&labelColor=white)](https://a-sit-plus.github.io)
[![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-orange.svg?logo=kotlin)](http://kotlinlang.org)
[![Kotlin](https://img.shields.io/badge/kotlin-2.0.0-blue.svg?logo=kotlin)](http://kotlinlang.org)
[![Kotlin](https://img.shields.io/badge/kotlin-2.0.20-blue.svg?logo=kotlin)](http://kotlinlang.org)
[![Java](https://img.shields.io/badge/java-17+-blue.svg?logo=OPENJDK)](https://www.oracle.com/java/technologies/downloads/#java11)

[![Maven Central (indispensable)](https://img.shields.io/maven-central/v/at.asitplus.signum/indispensable?label=maven-central%20%28indispensable%29)](https://mvnrepository.com/artifact/at.asitplus.signum/)
[![Maven SNAPSHOT (indispensable)](https://img.shields.io/nexus/snapshots/https/s01.oss.sonatype.org/at.asitplus.signum/indispensable?label=SNAPSHOT%20%28indispensable%29)](https://s01.oss.sonatype.org/content/repositories/snapshots/at/asitplus/signum/indispensable/)
[![Maven Central (Supreme)](https://img.shields.io/maven-central/v/at.asitplus.signum/supreme?label=maven-central%20%28Supreme%29)](https://mvnrepository.com/artifact/at.asitplus.signum/supreme)
[![Maven SNAPSHOT (Supreme)](https://img.shields.io/nexus/snapshots/https/s01.oss.sonatype.org/at.asitplus.signum/supreme?label=SNAPSHOT%20%28Supreme%29)](https://s01.oss.sonatype.org/content/repositories/snapshots/at/asitplus/signum/supreme/)

</div>

Expand Down Expand Up @@ -383,47 +386,76 @@ Which results in the following output:
### Working with Generic ASN.1 Structures

The magic shown above is based on a from-scratch 100% KMP implementation of an ASN.1 encoder and parser.
To parse any DER-encoded ASN.1 structure, call `Asn1Element.parse(derBytes)`, which will result in exactly a single
`Asn1Element`.
It can be re-encoded (and yes, it is a true re-encoding, since the original bytes are discarded after decoding) by
accessing the lazily evaluated `.derEncoded` property.
To parse any DER-encoded ASN.1 structure, call either:

* `Asn1Element.parse()`, which will consume all bytes and return the first parsed ASN.1 element.
This method throws if parsing errors occur or any trailing bytes are left after parsing the first element.
* `Asn1Element.parseFirst()`, which will try to parse a single toplevel ASN.1 element.
Any remaining bytes can still be consumed from the iterator, as it will only be advanced to right after the first parsed element.
* `Asn1Element.parseAll()`, wich consumes all bytes, parses all toplevel ASN.1 elements, and returns them as list.
Throws on any parsing error.

`Asn1Element`s can encoded by accessing the lazily evaluated `.derEncoded` property.
Even for parsed elements, this is a true re-encoding. The original bytes are discarded after decoding.

**Note that decoding operations will throw exceptions if invalid data is provided!**

A parsed `Asn1Element` can either be a primitive (whose tag and value can be read) or a structure (like a set or
sequence) whose child
nodes can be processed as desired. Subclasses of `Asn1Element` reflect this:
sequence) whose child nodes can be processed as desired. Subclasses of `Asn1Element` reflect this:

* `Asn1Primitive`
* `Asn1BitString` (for convenience)
* `Asn1PrimitiveOctetString` (for convenience)
* `Asn1Structure`
* `Asn1Set`
* `Asn1Sequence`

* `Asn1Sequence` and `Asn1SequenceOf`
* `Asn1Set` and `Asn1SetOf` (sorting children by default)
* `Asn1EncapsulatingOctetString` (tagged as OCTET STRING, containing a valid ASN.1 structure or primitive)
* `Asn1ExplicitlyTagged` (user-specified tag + CONTEXT_SPECIFIC + CONSTRUCTED)
* `Asn1CustomStructure` (any other CONSTRUCTED tag not fitting the above options. CONSTRUCTED bit may be overridden)

Convenience wrappers exist, to cast to any subtype (e.g. `.asSequence()`). These shorthand functions throw an `Asn1Exception`
if a cast is not possible.
Any complex data structure (such as CSR, public key, certificate, …) implements `Asn1Encodable`, which means you can:

* encapsulate it into an ASN.1 Tree by calling `.encodeToTlv()`
* directly get a DER-encoded byte array through the `.encodetoDer()` function

To also suport going the other way, the companion objects of these complex classes implement `Asn1Decodable`, which
allows for
A tandem of helper functions is available for primitives (numbers, booleans, string, bigints):

* directly parsing DER-encoded byte arrays by calling `.decodeFromDer(bytes)`
* processing an `Asn1Element` by calling `.fromTlv(src)`
* `encodeToAsn1Primitive` to produce an `Asn1Primitive` that can directly be DER-encoded
* `encodeToAsn1ContentBytes` to produce the content bytes of a TLV primitive (the _V_ in TLV)

Variations of these exist for `Instant` and `ByteArray`.

Check out [Asn1Encoding.kt](indispensable/src/commonMain/kotlin/at/asitplus/signum/indispensable/asn1/encoding/Asn1Encoding.kt) for a full
list of helper functions.

#### Decoding Values

Various helper functions exist to facilitate decoging the values contained in `Asn1Primitives`, such as `decodeInt()`,
for example.
Various helper functions exist to facilitate decoding the values contained in `Asn1Primitives`, such as `readInt()`,
for example. To also support decoding more complex structures, the companion objects of complex classes (such as certificates, CSRs, …)
implement `Asn1Decodable`, which allows for:

* directly parsing DER-encoded byte arrays by calling `.decodeFromDer(bytes)` and `.decodeFromDerHexString`
* processing an `Asn1Element` by calling `.decodefromTlv(src)`

Both encoding and decoding functions come in two _safe_ (i.e. non-throwing) variants:
* `…Safe()` which returns a [KmmResult](https://github.com/a-sit-plus/kmmresult)
* `…orNull()` which returns null on error

Similarly to encoding, a tandem of decoding functions exists for primitives:
* `decodeToXXX` to be invoked on an `Asn1Primitive` to decode a DER-encoded primitive into the target type
* `decodeFromAsn1ContentBytes` to be invoked on the companion of the target type to decode the content bytes of a TLV primitive (the _V_ in TLV)

However, anything can be decoded and tagged at will. Therefore, a generic decoding function exists, which has the
following signature:

```kotlin
inline fun <reified T> Asn1Primitive.decode(tag: UByte, decode: (content: ByteArray) -> T)
inline fun <reified T> Asn1Primitive.decode(assertTag: Asn1Element.Tag, decode: (content: ByteArray) -> T)
```

Check out [Asn1Reader.kt](datatypes/src/commonMain/kotlin/at/asitplus/crypto/datatypes/asn1/Asn1Reader.kt) for a full
list
of helper functions.
Check out [Asn1Decoding.kt](indispensable/src/commonMain/kotlin/at/asitplus/signum/indispensable/asn1/encoding/Asn1Decoding.kt) for a full
list of helper functions.

#### ASN1 DSL for Creating ASN.1 Structures

Expand All @@ -432,72 +464,77 @@ DSL, which returns an `Asn1Structure`:

```kotlin
Asn1.Sequence {
+Tagged(1u) {
+Asn1Primitive(BERTags.BOOLEAN, byteArrayOf(0x00))
}
+Asn1.Set {
+Asn1.Sequence {
+Asn1.SetOf {
+PrintableString("World")
+PrintableString("Hello")
}
+Asn1.Set {
+PrintableString("World")
+PrintableString("Hello")
+Utf8String("!!!")
}

}
+ExplicitlyTagged(1uL) {
+Asn1Primitive(Asn1Element.Tag.BOOL, byteArrayOf(0x00)) //or +Asn1.Bool(false)
}
+Asn1.Set {
+Asn1.Sequence {
+Asn1.SetOf {
+PrintableString("World")
+PrintableString("Hello")
}
+Asn1.Set {
+PrintableString("World")
+PrintableString("Hello")
+Utf8String("!!!")
}

}
+Asn1.Null()
}
+Asn1.Null()

+ObjectIdentifier("1.2.603.624.97")
+ObjectIdentifier("1.2.603.624.97")

+Utf8String("Foo")
+PrintableString("Bar")
+(Utf8String("Foo") withImplicitTag (0xCAFEuL withClass TagClass.PRIVATE))
+PrintableString("Bar")

+Asn1.Set {
+Asn1.Int(3)
+Asn1.Long(-65789876543L)
+Asn1.Bool(false)
+Asn1.Bool(true)
}
+Asn1.Sequence {
+Asn1.Null()
+Asn1String.Numeric("12345")
+UtcTime(Clock.System.now())
}
}
//fake Primitive
+(Asn1.Sequence { +Asn1.Int(42) } withImplicitTag (0x5EUL without CONSTRUCTED))

+Asn1.Set {
+Asn1.Int(3)
+Asn1.Int(-65789876543L)
+Asn1.Bool(false)
+Asn1.Bool(true)
}
+Asn1.Sequence {
+Asn1.Null()
+Asn1String.Numeric("12345")
+UtcTime(Clock.System.now())
}
} withImplicitTag (1337uL withClass TagClass.APPLICATION)
```

In accordance with DER-Encoding, this produces the following ASN.1 structure:

```
SEQUENCE (8 elem)
[1] (1 elem)
BOOLEAN false
SET (1 elem)
SEQUENCE (2 elem)
SET (2 elem)
PrintableString Hello
PrintableString World
SET (3 elem)
UTF8String !!!
PrintableString World
PrintableString Hello
NULL
OBJECT IDENTIFIER 1.2.603.624.97
UTF8String Foo
PrintableString Bar
SET (4 elem)
BOOLEAN false
BOOLEAN true
INTEGER 3
INTEGER (36 bit) -65789876543
SEQUENCE (3 elem)
Application 1337 (9 elem)

[1] (1 elem)
BOOLEAN false
SET (1 elem)
SEQUENCE (2 elem)
SET (2 elem)
PrintableString World
PrintableString Hello
SET (3 elem)
UTF8String !!!
PrintableString World
PrintableString Hello
NULL
NumericString 12345
UTCTime 2023-10-21 21:14:49 UTC
OBJECT IDENTIFIER 1.2.603.624.97
Private 51966 (3 byte) Foo
PrintableString Bar
[94] (3 byte) 02012A
SET (4 elem)
BOOLEAN false
BOOLEAN true
INTEGER 3
INTEGER (36 bit) -65789876543
SEQUENCE (3 elem)
NULL
NumericString 12345
UTCTime 2024-09-16 11:53:51 UTC
```

## Limitations
Expand Down
9 changes: 7 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import org.jetbrains.dokka.gradle.DokkaMultiModuleTask

plugins {
id("at.asitplus.gradle.conventions") version "2.0.20+20240829"
id("at.asitplus.gradle.conventions") version "2.0.20+20240920"
id("com.android.library") version "8.2.2" apply (false)
}
group = "at.asitplus.signum"

//work around nexus publish bug
val artifactVersion: String by extra
version = artifactVersion
//end work around nexus publish bug


//access dokka plugin from conventions plugin's classpath in root project → no need to specify version
apply(plugin = "org.jetbrains.dokka")
Expand All @@ -26,7 +31,7 @@ tasks.getByName("dokkaHtmlMultiModule") {
"josef-light.png",
"signum-light-large.png",
"signum-dark-large.png",
).files.forEach { it.copyTo(File("build/dokka/${it.name}"), overwrite = true) }
).files.forEach { it.copyTo(File("build/dokka/${it.name}"), overwrite = true) }
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ internal fun App() {
} ?: ""
}
val verifyPossible by getter { signatureData?.isSuccess == true }
var verifyState by remember { mutableStateOf<KmmResult<Unit>?>(null) }
var verifyState by remember { mutableStateOf<KmmResult<Success>?>(null) }
val verifySucceededStr by getter {
verifyState?.fold(onSuccess = {
"Verify OK!"
Expand Down
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ kotlin.code.style=official
kotlin.js.compiler=ir
org.gradle.jvmargs=-Xmx4g -Dfile.encoding=UTF-8

artifactVersion=3.7.0
supremeVersion=0.2.0
artifactVersion=3.8.0
supremeVersion=0.3.0

# This is not a well-defined property, the ASP convention plugin respects it, though
jdk.version=17
Expand Down
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ bignum = "0.3.10"
jose = "9.31"
kotlinpoet = "1.16.0"
runner = "1.5.2"
kotest-plugin = "20240918.002009-71"

[libraries]
bignum = { group = "com.ionspin.kotlin", name = "bignum", version.ref = "bignum" }
Expand Down
1 change: 1 addition & 0 deletions indispensable-cosef/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ kotlin {

exportIosFramework(
"IndispensableCosef",
transitiveExports=false,
serialization("cbor"),
datetime(),
kmmresult(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import at.asitplus.catching
import at.asitplus.signum.indispensable.CryptoPublicKey
import at.asitplus.signum.indispensable.SignatureAlgorithm
import at.asitplus.signum.indispensable.SpecializedCryptoPublicKey
import at.asitplus.signum.indispensable.asn1.encodeToByteArray
import at.asitplus.signum.indispensable.asn1.encoding.toTwosComplementByteArray
import at.asitplus.signum.indispensable.cosef.CoseKey.Companion.deserialize
import at.asitplus.signum.indispensable.cosef.CoseKeySerializer.CompressedCompoundCoseKeySerialContainer
import at.asitplus.signum.indispensable.cosef.CoseKeySerializer.UncompressedCompoundCoseKeySerialContainer
Expand Down Expand Up @@ -187,7 +187,7 @@ fun CryptoPublicKey.toCoseKey(algorithm: CoseAlgorithm? = null, keyId: ByteArray
CoseKey(
keyParams = CoseKeyParams.RsaParams(
n = n,
e = e.encodeToByteArray()
e = e.toTwosComplementByteArray()
),
type = CoseKeyType.RSA,
keyId = didEncoded.encodeToByteArray(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import at.asitplus.KmmResult.Companion.failure
import at.asitplus.catching
import at.asitplus.signum.indispensable.CryptoPublicKey
import at.asitplus.signum.indispensable.SpecializedCryptoPublicKey
import at.asitplus.signum.indispensable.asn1.decodeFromDer
import at.asitplus.signum.indispensable.asn1.encoding.decodeFromAsn1ContentBytes

/**
* Wrapper to handle parameters for different COSE public key types.
Expand Down Expand Up @@ -164,7 +164,7 @@ sealed class CoseKeyParams : SpecializedCryptoPublicKey {
override fun toCryptoPublicKey(): KmmResult<CryptoPublicKey> = catching {
CryptoPublicKey.Rsa(
n = n ?: throw IllegalArgumentException("Missing modulus n"),
e = Int.decodeFromDer(e ?:
e = Int.decodeFromAsn1ContentBytes(e ?:
throw IllegalArgumentException("Missing or invalid exponent e"))
)
}
Expand Down
Loading
Loading