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

Provider: Signing #94

Merged
merged 73 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
6f5c8c4
Signing
iaik-jheher Jul 8, 2024
40b96b5
android fixes + signer cleanup
iaik-jheher Aug 23, 2024
fce2734
attestation
iaik-jheher Aug 23, 2024
25a5b68
look at all of these lines of code that we aren't writing
iaik-jheher Aug 23, 2024
be68019
cleanup xcode artefacts
iaik-jheher Aug 23, 2024
0c66aa4
ios attestation adjustments
iaik-jheher Aug 23, 2024
264e2b3
ephemeral keys
iaik-jheher Aug 26, 2024
15fb42b
ios ephemeral keys
iaik-jheher Aug 26, 2024
47ec231
change defaults for ephemeral keys to be super permissive
iaik-jheher Aug 26, 2024
0dd5845
ios digest cleanup
iaik-jheher Aug 27, 2024
e17a2d6
JKS provider
iaik-jheher Aug 27, 2024
a0641bc
JKS provider
iaik-jheher Aug 27, 2024
cf5a58d
expose ephemeral key internal object
iaik-jheher Aug 27, 2024
8810095
annotate our own usages
iaik-jheher Aug 27, 2024
706959d
ephemerals arrrgh
iaik-jheher Aug 27, 2024
fd13988
Revert "ephemerals arrrgh"
iaik-jheher Aug 27, 2024
d88b319
ephemeral internals but nicer
iaik-jheher Aug 27, 2024
64bb2b9
hazmat cleanup
iaik-jheher Aug 28, 2024
1c5ed2b
experimentals opt-in
iaik-jheher Aug 28, 2024
ce91f4f
missing import
iaik-jheher Aug 28, 2024
56f30a3
bump sumpreme version
JesusMcCloud Aug 28, 2024
7ff5e4b
update kotlin+kotest
JesusMcCloud Aug 28, 2024
c0f9577
platform signer cleanup
iaik-jheher Aug 28, 2024
d0a64a3
KT-71036 workaround
iaik-jheher Aug 28, 2024
961ff67
activity lifecycle callbacks on android
iaik-jheher Aug 28, 2024
10bfc0a
Revert "update kotlin+kotest"
iaik-jheher Aug 28, 2024
522c613
dummy out platform-agnostic provider construction until KT-71036 is f…
iaik-jheher Aug 28, 2024
d75e70b
ios timeout
iaik-jheher Aug 28, 2024
de918b1
don't overwrite existing keys
iaik-jheher Aug 28, 2024
d529b2a
version updates, changelog, ang fixes
JesusMcCloud Aug 28, 2024
b18ea9f
fix jvm compile error
JesusMcCloud Aug 28, 2024
e40c349
partial documentation commit
iaik-jheher Aug 29, 2024
c9c8ae2
fix testcase after rename
iaik-jheher Aug 29, 2024
ee0e0d5
revert partial change that never happened
iaik-jheher Aug 29, 2024
3734d3a
cleanup build files
JesusMcCloud Aug 29, 2024
3bcd70e
update AGP
JesusMcCloud Aug 29, 2024
8468cd3
the documentation commit
iaik-jheher Aug 29, 2024
fd45323
update AGP
JesusMcCloud Aug 29, 2024
c6437b9
WIP
iaik-jheher Aug 29, 2024
9fa0569
build fixes
iaik-jheher Aug 29, 2024
3495542
always pre-hash on ios
iaik-jheher Aug 29, 2024
5b612d1
fix demoapp build
JesusMcCloud Aug 29, 2024
7bef269
the second coming of Signer, iOS edition
iaik-jheher Aug 30, 2024
9b6827f
now also on android
iaik-jheher Aug 30, 2024
6de1296
requested adjustments android edition
iaik-jheher Sep 2, 2024
4086154
requested changes ios edition
iaik-jheher Sep 2, 2024
0d98161
fix ios cancellation detection
iaik-jheher Sep 2, 2024
059a4f3
fix ios cancellation detection
iaik-jheher Sep 2, 2024
d64de45
pin android to single thread
iaik-jheher Sep 2, 2024
b98104c
readme
iaik-jheher Sep 2, 2024
fc72ad0
delete the readme compile tests since @JesusMcCloud deleted the depen…
iaik-jheher Sep 2, 2024
ae1f93b
test case fixes for kotlin 2.0.20
iaik-jheher Sep 2, 2024
ada7600
cleanup demoapp readme
JesusMcCloud Sep 3, 2024
01c2286
cleanup build files
JesusMcCloud Sep 3, 2024
5c6b68a
fix comment in build file
JesusMcCloud Sep 3, 2024
f86e857
fix developmen.md for demo app
JesusMcCloud Sep 3, 2024
eef462b
workaround android keystore bug
iaik-jheher Sep 3, 2024
68ff176
current-set biometry on ios
iaik-jheher Sep 3, 2024
fb96c9e
signatureresult transforming
iaik-jheher Sep 3, 2024
e67557a
star wars
iaik-jheher Sep 3, 2024
da90b11
fix jvm clash
iaik-jheher Sep 3, 2024
a3f9959
add link to readme
iaik-jheher Sep 3, 2024
becb46f
throws annotation as requested
iaik-jheher Sep 3, 2024
7c8293a
Revert "throws annotation as requested" (because it breaks iOS)
iaik-jheher Sep 3, 2024
a7072e1
requested documentation
iaik-jheher Sep 4, 2024
5767057
sign() always returns RawByteEncodable signatures
iaik-jheher Sep 4, 2024
694c2ac
fix andorid
iaik-jheher Sep 4, 2024
beeb94f
demoapp jvm support
iaik-jheher Sep 4, 2024
79275cf
it's-a-read-me, mario
iaik-jheher Sep 4, 2024
c6f0815
Oklahoma
JesusMcCloud Sep 4, 2024
0db13dc
attestation repudiation commit
iaik-jheher Sep 4, 2024
432693d
remove kmp-crypto remnants
JesusMcCloud Sep 4, 2024
910ccc6
fix jks testcase
JesusMcCloud Sep 4, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,15 @@ class AndroidSignerSigningConfiguration: PlatformSigningProviderSignerSigningCon
}

/**
* Resolve [what] differently based on whether the [v]alue was [spec]ified.
* Resolve [what] differently based on whether the [vA]lue was [spec]ified.
*
* * [spec] = `true`: Check if [valid] contains [nameMap] applied to [v], return [v] if yes, throw otherwise
* * [spec] = `true`: Check if [valid] contains [nameMap] applied to [vA()][vA], return [vA()][vA] if yes, throw otherwise
* * [spec] = `false`: Check if [valid] contains exactly one element, if yes, return the [E] from [possible] for which [nameMap] returns that element, throw otherwise
*/
internal inline fun <reified E> resolveOption(what: String, valid: Array<String>, possible: Sequence<E>, spec: Boolean, v: E, crossinline nameMap: (E)->String): E =
internal inline fun <reified E> resolveOption(what: String, valid: Array<String>, possible: Sequence<E>, spec: Boolean, vA: ()->E, crossinline nameMap: (E)->String): E =
when (spec) {
true -> {
val v = vA()
val vStr = nameMap(v)
if (!valid.any { it.equals(vStr, ignoreCase=true) })
throw IllegalArgumentException("Key does not support $what $v; supported: ${valid.joinToString(", ")}")
Expand Down Expand Up @@ -223,13 +224,13 @@ object AndroidKeyStoreProvider:
val algorithm = when (val publicKey = certificateChain.leaf.publicKey) {
is CryptoPublicKey.EC -> {
val ecConfig = config.ec.v
val digest = resolveOption("digest", keyInfo.digests, Digest.entries.asSequence() + sequenceOf<Digest?>(null), ecConfig.digestSpecified, ecConfig.digest) { it?.jcaName ?: KeyProperties.DIGEST_NONE }
val digest = resolveOption("digest", keyInfo.digests, Digest.entries.asSequence() + sequenceOf<Digest?>(null), ecConfig.digestSpecified, { ecConfig.digest }) { it?.jcaName ?: KeyProperties.DIGEST_NONE }
SignatureAlgorithm.ECDSA(digest, publicKey.curve)
}
is CryptoPublicKey.Rsa -> {
val rsaConfig = config.rsa.v
val digest = resolveOption<Digest>("digest", keyInfo.digests, Digest.entries.asSequence(), rsaConfig.digestSpecified, rsaConfig.digest, Digest::jcaName)
val padding = resolveOption<RSAPadding>("padding", keyInfo.signaturePaddings, RSAPadding.entries.asSequence(), rsaConfig.paddingSpecified, rsaConfig.padding) {
val digest = resolveOption<Digest>("digest", keyInfo.digests, Digest.entries.asSequence(), rsaConfig.digestSpecified, { rsaConfig.digest }, Digest::jcaName)
val padding = resolveOption<RSAPadding>("padding", keyInfo.signaturePaddings, RSAPadding.entries.asSequence(), rsaConfig.paddingSpecified, { rsaConfig.padding }) {
when (it) {
RSAPadding.PKCS1 -> KeyProperties.SIGNATURE_PADDING_RSA_PKCS1
RSAPadding.PSS -> KeyProperties.SIGNATURE_PADDING_RSA_PSS
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package at.asitplus.signum.supreme.sign

import android.security.keystore.KeyProperties
import at.asitplus.catching
import at.asitplus.signum.indispensable.CryptoPublicKey
import at.asitplus.signum.indispensable.CryptoSignature
import at.asitplus.signum.indispensable.SignatureAlgorithm
import at.asitplus.signum.indispensable.fromJcaPublicKey
import at.asitplus.signum.indispensable.getJCASignatureInstancePreHashed
import at.asitplus.signum.indispensable.jcaName
import at.asitplus.signum.indispensable.parseFromJca
import at.asitplus.signum.supreme.signCatching
import com.ionspin.kotlin.bignum.integer.base63.toJavaBigInteger
import java.security.KeyPairGenerator
import java.security.PrivateKey
Expand All @@ -20,7 +20,7 @@ actual class EphemeralSignerConfiguration internal actual constructor(): Ephemer

sealed class AndroidEphemeralSigner (internal val privateKey: PrivateKey) : Signer {
override val mayRequireUserUnlock = false
override suspend fun sign(data: SignatureInput) = catching {
override suspend fun sign(data: SignatureInput) = signCatching {
val inputData = data.convertTo(signatureAlgorithm.preHashedSignatureFormat).getOrThrow()
signatureAlgorithm.getJCASignatureInstancePreHashed(provider = null).getOrThrow().run {
initSign(privateKey)
Expand Down Expand Up @@ -57,7 +57,7 @@ internal actual fun makeEphemeralKey(configuration: EphemeralSigningKeyConfigura
generateKeyPair()
}.let { pair ->
EphemeralKeyBase.RSA(AndroidEphemeralSigner::RSA,
pair.private, CryptoPublicKey.fromJcaPublicKey(pair.public) as CryptoPublicKey.Rsa,
pair.private, CryptoPublicKey.fromJcaPublicKey(pair.public).getOrThrow() as CryptoPublicKey.Rsa,
digests = alg.digests, paddings = alg.paddings)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package at.asitplus.signum.supreme.os

import at.asitplus.KmmResult
import at.asitplus.catching
import at.asitplus.signum.indispensable.CryptoSignature
import at.asitplus.signum.indispensable.Digest
import at.asitplus.signum.indispensable.RSAPadding
import at.asitplus.signum.supreme.SignatureResult
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
package at.asitplus.signum.supreme.sign

import at.asitplus.KmmResult
import at.asitplus.catching
import at.asitplus.signum.indispensable.CryptoPublicKey
import at.asitplus.signum.indispensable.CryptoSignature
import at.asitplus.signum.indispensable.Digest
import at.asitplus.signum.indispensable.ECCurve
import at.asitplus.signum.indispensable.RSAPadding
import at.asitplus.signum.indispensable.SignatureAlgorithm
import at.asitplus.signum.indispensable.nativeDigest
import at.asitplus.signum.supreme.HazardousMaterials
import at.asitplus.signum.supreme.SignatureResult
import at.asitplus.signum.supreme.UnlockFailed
import at.asitplus.signum.supreme.dsl.DSL
import at.asitplus.signum.supreme.dsl.DSLConfigureFn
import at.asitplus.signum.supreme.os.Attestation
import at.asitplus.signum.supreme.os.SigningProvider
import com.ionspin.kotlin.bignum.integer.BigInteger
import io.matthewnelson.encoding.base16.Base16

/** DSL for configuring a signing key.
*
Expand Down Expand Up @@ -74,13 +69,13 @@ open class SigningKeyConfiguration internal constructor(): DSL.Data() {
* ```
* This will generate a throwaway [EphemeralKey] and return a Signer for it.
*
* Any actual instantiation will have a [AlgTrait], which will be either [ECDSA] or [RSA].
* Any actual instantiation will have an [AlgTrait], which will be either [ECDSA] or [RSA].
* Instantiations may also be [WithAlias], usually because they come from a [SigningProvider].
* They may also be [Attestable].
*
* Some signers [mayRequireUserUnlock]. If needed, they will ask for user interaction when you try to [sign] data.
* Of these signers, some are also [Signer.TemporarilyUnlockable].
* These signers can be used to sign multiple times in rapid succession with only a single user interaction.
* You can try to authenticate a signer ahead of time using [trySetupUninterruptedSigning]; but it might do nothing for some Signers.
* There is never a guarantee that signing is uninterrupted if [mayRequireUserUnlock] is true.
*
*/
interface Signer {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import kotlin.native.ref.createCleaner

@OptIn(ExperimentalNativeApi::class)
class AutofreeVariable<T: CPointer<*>> internal constructor(
private val arena: Arena,
arena: Arena,
private val variable: CPointerVarOf<T>) {
companion object {
internal inline operator fun <reified T: CPointer<*>> invoke(): AutofreeVariable<T> {
Expand All @@ -38,6 +38,7 @@ class AutofreeVariable<T: CPointer<*>> internal constructor(
return AutofreeVariable<T>(arena, variable)
}
}
@Suppress("UNUSED")
private val cleaner = createCleaner(arena, Arena::clear)
internal val ptr get() = variable.ptr
internal val value get() = variable.value
Expand All @@ -55,14 +56,14 @@ internal fun ByteArray.toNSData(): NSData = memScoped {
}

private fun NSError.toNiceString(): String {
val sb = StringBuilder("[Code $code] $localizedDescription\n")
val sb = StringBuilder("[${if(domain != null) "$domain error, " else ""}code $code] $localizedDescription\n")
localizedFailureReason?.let { sb.append("Because: $it") }
localizedRecoverySuggestion?.let { sb.append("Try: $it") }
localizedRecoveryOptions?.let { sb.append("Try also:\n - ${it.joinToString("\n - ")}\n") }
return sb.toString()
}

class CFCryptoOperationFailed(thing: String, osStatus: OSStatus) : CryptoOperationFailed(buildMessage(thing, osStatus)) {
class CFCryptoOperationFailed(thing: String, val osStatus: OSStatus) : CryptoOperationFailed(buildMessage(thing, osStatus)) {
companion object {
private fun buildMessage(thing: String, osStatus: OSStatus): String {
val errorMessage = SecCopyErrorMessageString(osStatus, null).takeFromCF<String?>()
Expand All @@ -71,7 +72,7 @@ class CFCryptoOperationFailed(thing: String, osStatus: OSStatus) : CryptoOperati
}
}

class CoreFoundationException(message: String): Throwable(message)
class CoreFoundationException(val nsError: NSError): Throwable(nsError.toNiceString())
internal class corecall private constructor(val error: CPointer<CFErrorRefVar>) {
/** Helper for calling Core Foundation functions, and bridging exceptions across.
*
Expand All @@ -92,7 +93,7 @@ internal class corecall private constructor(val error: CPointer<CFErrorRefVar>)
when {
(result != null) && (error == null) -> return result
(result == null) && (error != null) ->
throw CoreFoundationException(error.takeFromCF<NSError>().toNiceString())
throw CoreFoundationException(error.takeFromCF<NSError>())
else -> throw IllegalStateException("Invalid state returned by Core Foundation call")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,19 +96,24 @@ import platform.Security.kSecReturnRef
import platform.Security.kSecUseAuthenticationContext
import platform.Security.kSecUseAuthenticationUI
import platform.Security.kSecUseAuthenticationUIAllow
import at.asitplus.signum.indispensable.secKeyAlgorithm
import at.asitplus.signum.indispensable.secKeyAlgorithmPreHashed
import at.asitplus.signum.supreme.AutofreeVariable
import at.asitplus.signum.supreme.CoreFoundationException
import at.asitplus.signum.supreme.SignatureResult
import at.asitplus.signum.supreme.UnlockFailed
import at.asitplus.signum.supreme.sign.SigningKeyConfiguration
import at.asitplus.signum.supreme.sign.preHashedSignatureFormat
import at.asitplus.signum.supreme.signCatching
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import platform.LocalAuthentication.LAErrorAuthenticationFailed
import platform.LocalAuthentication.LAErrorBiometryLockout
import platform.LocalAuthentication.LAErrorDomain
import platform.LocalAuthentication.LAErrorUserCancel
import platform.Security.errSecAuthFailed
import platform.Security.errSecUnsupportedKeyFormat
import platform.Security.errSecUserCanceled
import platform.Security.kSecUseAuthenticationUIFail
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.math.min
import kotlin.time.Duration
import kotlin.time.TimeSource
Expand Down Expand Up @@ -148,14 +153,15 @@ class IosSigningKeyConfiguration internal constructor(): PlatformSigningKeyConfi
}

/**
* Resolve [what] differently based on whether the [v]alue was [spec]ified.
* Resolve [what] differently based on whether the [vA]lue was [spec]ified.
*
* * [spec] = `true`: Check if [valid] contains [v], return [v] if yes, throw otherwise
* * [spec] = `true`: Check if [valid] contains [vA()][vA], return [vA()][vA] if yes, throw otherwise
* * [spec] = `false`: Check if [valid] contains exactly one element, if yes, return it, throw otherwise
*/
private inline fun <reified E> resolveOption(what: String, valid: Set<E>, spec: Boolean, v: E): E =
private inline fun <reified E> resolveOption(what: String, valid: Set<E>, spec: Boolean, vA: ()->E): E =
when (spec) {
true -> {
val v = vA()
if (!valid.contains(v))
throw IllegalArgumentException("Key does not support $what $v; supported: ${valid.joinToString(", ")}")
v
Expand Down Expand Up @@ -212,10 +218,10 @@ sealed class IosSigner(final override val alias: String,
}
ctx.apply {
val stack = DSL.ConfigStack(signingConfig.unlockPrompt.v, signerConfig.unlockPrompt.v)
localizedReason = stack.getProperty(UnlockPromptConfiguration::message,
checker = UnlockPromptConfiguration::messageSpecified, default = UnlockPromptConfiguration.defaultMessage)
localizedCancelTitle = stack.getProperty(UnlockPromptConfiguration::cancelText,
checker = UnlockPromptConfiguration::cancelTextSpecified, default = UnlockPromptConfiguration.defaultCancelText)
localizedReason = stack.getProperty(UnlockPromptConfiguration::_message,
default = UnlockPromptConfiguration.defaultMessage)
localizedCancelTitle = stack.getProperty(UnlockPromptConfiguration::_cancelText,
default = UnlockPromptConfiguration.defaultCancelText)
}
} else {
recordable = false
Expand Down Expand Up @@ -292,9 +298,21 @@ sealed class IosSigner(final override val alias: String,
val signingConfig = DSL.resolve(::IosSignerSigningConfiguration, configure)
val algorithm = signatureAlgorithm.secKeyAlgorithmPreHashed
val plaintext = data.convertTo(signatureAlgorithm.preHashedSignatureFormat).getOrThrow().data.first().toNSData()
val signatureBytes = corecall {
SecKeyCreateSignature(privateKeyManager.get(signingConfig).value, algorithm, plaintext.giveToCF(), error)
}.takeFromCF<NSData>().toByteArray()
val signatureBytes = try {
corecall {
SecKeyCreateSignature(privateKeyManager.get(signingConfig).value, algorithm, plaintext.giveToCF(), error)
}.takeFromCF<NSData>().toByteArray()
} catch (x: CoreFoundationException) { /* secure enclave failure */
if (x.nsError.domain == LAErrorDomain) when (x.nsError.code) {
LAErrorUserCancel, LAErrorAuthenticationFailed, LAErrorBiometryLockout -> throw UnlockFailed(x.nsError.localizedDescription, x)
else -> throw x
} else throw x
} catch (x: CFCryptoOperationFailed) { /* keychain failure */
when (x.osStatus) {
errSecUserCanceled, errSecAuthFailed -> throw UnlockFailed(x.message, x)
else -> throw x
}
}
return@signCatching bytesToSignature(signatureBytes)
}}

Expand All @@ -308,7 +326,7 @@ sealed class IosSigner(final override val alias: String,
{ "Metadata type mismatch (ECDSA key, metadata not ECDSA)" }

signatureAlgorithm = when (
val digest = resolveOption("digest", metadata.algSpecific.supportedDigests, config.ec.v.digestSpecified, config.ec.v.digest)
val digest = resolveOption("digest", metadata.algSpecific.supportedDigests, config.ec.v.digestSpecified, { config.ec.v.digest })
){
Digest.SHA256, Digest.SHA384, Digest.SHA512 -> SignatureAlgorithm.ECDSA(digest, publicKey.curve)
else -> throw UnsupportedCryptoException("ECDSA with $digest is not supported on iOS")
Expand All @@ -328,8 +346,8 @@ sealed class IosSigner(final override val alias: String,
{ "Metadata type mismatch (RSA key, metadata not RSA) "}

signatureAlgorithm = SignatureAlgorithm.RSA(
digest = resolveOption("digest", metadata.algSpecific.supportedDigests, config.rsa.v.digestSpecified, config.rsa.v.digest),
padding = resolveOption("padding", metadata.algSpecific.supportedPaddings, config.rsa.v.paddingSpecified, config.rsa.v.padding)
digest = resolveOption("digest", metadata.algSpecific.supportedDigests, config.rsa.v.digestSpecified, { config.rsa.v.digest }),
padding = resolveOption("padding", metadata.algSpecific.supportedPaddings, config.rsa.v.paddingSpecified, { config.rsa.v.padding })
JesusMcCloud marked this conversation as resolved.
Show resolved Hide resolved
)
}
override fun bytesToSignature(sigBytes: ByteArray) =
Expand Down Expand Up @@ -501,7 +519,7 @@ object IosKeychainProvider: PlatformSigningProviderI<IosSigner, IosSignerConfigu
}.let { it.takeFromCF<NSData>() }.toByteArray()
} else {
val x = CFCryptoOperationFailed(thing = "generate key", osStatus = status)
if ((status == -50) &&
if ((status == errSecUnsupportedKeyFormat) &&
useSecureEnclave &&
!isSecureEnclaveSupportedConfiguration(config._algSpecific.v)) {
throw UnsupportedCryptoException("iOS Secure Enclave does not support this configuration.", x)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
@file:OptIn(ExperimentalForeignApi::class)
package at.asitplus.signum.supreme.sign

import at.asitplus.catching
import at.asitplus.signum.indispensable.CryptoPublicKey
import at.asitplus.signum.indispensable.CryptoSignature
import at.asitplus.signum.indispensable.SignatureAlgorithm
Expand All @@ -12,6 +11,7 @@ import at.asitplus.signum.supreme.cfDictionaryOf
import at.asitplus.signum.supreme.corecall
import at.asitplus.signum.supreme.createCFDictionary
import at.asitplus.signum.supreme.giveToCF
import at.asitplus.signum.supreme.signCatching
import at.asitplus.signum.supreme.takeFromCF
import at.asitplus.signum.supreme.toByteArray
import at.asitplus.signum.supreme.toNSData
Expand Down Expand Up @@ -41,14 +41,14 @@ actual class EphemeralSignerConfiguration internal actual constructor(): Ephemer
private typealias EphemeralKeyRef = AutofreeVariable<SecKeyRef>
sealed class EphemeralSigner(internal val privateKey: EphemeralKeyRef): Signer {
final override val mayRequireUserUnlock: Boolean get() = false
final override suspend fun sign(data: SignatureInput) = catching {
final override suspend fun sign(data: SignatureInput) = signCatching {
val inputData = data.convertTo(signatureAlgorithm.preHashedSignatureFormat).getOrThrow()
val algorithm = signatureAlgorithm.secKeyAlgorithmPreHashed
val input = inputData.data.single().toNSData()
val signatureBytes = corecall {
SecKeyCreateSignature(privateKey.value, algorithm, input.giveToCF(), error)
}.let { it.takeFromCF<NSData>().toByteArray() }
return@catching when (val pubkey = publicKey) {
return@signCatching when (val pubkey = publicKey) {
is CryptoPublicKey.EC -> CryptoSignature.EC.decodeFromDer(signatureBytes).withCurve(pubkey.curve)
is CryptoPublicKey.Rsa -> CryptoSignature.RSAorHMAC(signatureBytes)
}
Expand Down
Loading
Loading