From 9a98e79c76164555b19da6a4e77664d7d3b3e543 Mon Sep 17 00:00:00 2001 From: mimi89999 Date: Fri, 27 Mar 2026 00:03:20 +0100 Subject: [PATCH] Consolidate PIN and UV parameters in FIDO commands --- .../authnkey/CredentialProviderActivity.kt | 38 +++++++++-------- .../java/pl/lebihan/authnkey/FidoCommands.kt | 41 +++++++++++-------- .../java/pl/lebihan/authnkey/PinProtocol.kt | 16 +++----- 3 files changed, 50 insertions(+), 45 deletions(-) diff --git a/app/src/main/java/pl/lebihan/authnkey/CredentialProviderActivity.kt b/app/src/main/java/pl/lebihan/authnkey/CredentialProviderActivity.kt index 0d81711..cee7a96 100644 --- a/app/src/main/java/pl/lebihan/authnkey/CredentialProviderActivity.kt +++ b/app/src/main/java/pl/lebihan/authnkey/CredentialProviderActivity.kt @@ -858,10 +858,14 @@ class CredentialProviderActivity : AppCompatActivity() { } } - // Compute pinUvAuthParam if needed - var pinUvAuthParam: ByteArray? = null - if (pinProtocol != null) { - pinUvAuthParam = pinProtocol.computeAuthParam(clientData.hash) + // Build UV mode + val uvMode = if (pinProtocol != null && pinProtocol.hasPinToken()) { + FidoCommands.UvMode.AuthToken( + pinProtocol.computeAuthParam(clientData.hash), + protocol = 1 + ) + } else { + FidoCommands.UvMode.None } // Build and send command @@ -873,12 +877,10 @@ class CredentialProviderActivity : AppCompatActivity() { userName = userName, userDisplayName = userDisplayName, pubKeyCredParams = pubKeyCredParams, - excludeList = if (excludeList.isNotEmpty()) excludeList else null, + excludeList = excludeList.ifEmpty { null }, requireResidentKey = residentKey.requiresResidentKey(), - requireUserVerification = false, // UV is provided by pinUvAuthParam - extensions = if (ctapExtensions.isNotEmpty()) ctapExtensions else null, - pinUvAuthParam = pinUvAuthParam, - pinUvAuthProtocol = if (pinProtocol != null) 1 else null + uvMode = uvMode, + extensions = ctapExtensions.ifEmpty { null }, ) runOnUiThread { @@ -1085,21 +1087,23 @@ class CredentialProviderActivity : AppCompatActivity() { } } - // Compute pinUvAuthParam if needed - var pinUvAuthParam: ByteArray? = null - if (effectiveProtocol != null && effectiveProtocol.hasPinToken()) { - pinUvAuthParam = effectiveProtocol.computeAuthParam(clientData.hash) + // Build UV mode + val uvMode = if (effectiveProtocol != null && effectiveProtocol.hasPinToken()) { + FidoCommands.UvMode.AuthToken( + effectiveProtocol.computeAuthParam(clientData.hash), + protocol = 1 + ) + } else { + FidoCommands.UvMode.None } // Build and send command val command = FidoCommands.buildGetAssertion( rpId = rpId, clientDataHash = clientData.hash, - allowList = if (allowList.isNotEmpty()) allowList else null, - requireUserVerification = false, // UV is provided by pinUvAuthParam + allowList = allowList.ifEmpty { null }, + uvMode = uvMode, extensions = hmacSecretExtensions, - pinUvAuthParam = pinUvAuthParam, - pinUvAuthProtocol = if (effectiveProtocol != null && effectiveProtocol.hasPinToken()) 1 else null ) runOnUiThread { diff --git a/app/src/main/java/pl/lebihan/authnkey/FidoCommands.kt b/app/src/main/java/pl/lebihan/authnkey/FidoCommands.kt index efb33e5..0435066 100644 --- a/app/src/main/java/pl/lebihan/authnkey/FidoCommands.kt +++ b/app/src/main/java/pl/lebihan/authnkey/FidoCommands.kt @@ -4,6 +4,15 @@ import java.security.MessageDigest object FidoCommands { + sealed class UvMode { + /** No user verification requested. */ + object None : UvMode() + /** Ask the authenticator to perform UV itself. */ + object BuiltIn : UvMode() + /** UV via a pinUvAuth token. */ + data class AuthToken(val param: ByteArray, val protocol: Int) : UvMode() + } + fun buildMakeCredential( clientDataHash: ByteArray, rpId: String, @@ -14,10 +23,8 @@ object FidoCommands { pubKeyCredParams: List>, excludeList: List? = null, requireResidentKey: Boolean = true, - requireUserVerification: Boolean = true, + uvMode: UvMode = UvMode.None, extensions: Map? = null, - pinUvAuthParam: ByteArray? = null, - pinUvAuthProtocol: Int? = null ): ByteArray { val payload = cbor { map { @@ -62,14 +69,14 @@ object FidoCommands { } } - 7 to map { "rk" to requireResidentKey } - - if (pinUvAuthParam != null) { - 8 to bytes(pinUvAuthParam) + 7 to map { + "rk" to requireResidentKey + if (uvMode is UvMode.BuiltIn) "uv" to true } - if (pinUvAuthProtocol != null) { - 9 to pinUvAuthProtocol + if (uvMode is UvMode.AuthToken) { + 8 to bytes(uvMode.param) + 9 to uvMode.protocol } } } @@ -81,10 +88,8 @@ object FidoCommands { rpId: String, clientDataHash: ByteArray, allowList: List? = null, - requireUserVerification: Boolean = true, + uvMode: UvMode = UvMode.None, extensions: CborRaw? = null, - pinUvAuthParam: ByteArray? = null, - pinUvAuthProtocol: Int? = null ): ByteArray { val payload = cbor { map { @@ -106,14 +111,14 @@ object FidoCommands { 4 to extensions } - 5 to map { "up" to true } - - if (pinUvAuthParam != null) { - 6 to bytes(pinUvAuthParam) + 5 to map { + "up" to true + if (uvMode is UvMode.BuiltIn) "uv" to true } - if (pinUvAuthProtocol != null) { - 7 to pinUvAuthProtocol + if (uvMode is UvMode.AuthToken) { + 6 to bytes(uvMode.param) + 7 to uvMode.protocol } } } diff --git a/app/src/main/java/pl/lebihan/authnkey/PinProtocol.kt b/app/src/main/java/pl/lebihan/authnkey/PinProtocol.kt index aa65b1b..a35eec8 100644 --- a/app/src/main/java/pl/lebihan/authnkey/PinProtocol.kt +++ b/app/src/main/java/pl/lebihan/authnkey/PinProtocol.kt @@ -329,17 +329,13 @@ class PinProtocol(private val transport: FidoTransport) { val isInitialized: Boolean get() = sharedSecret != null && platformPublicKey != null - fun computeAuthParam(message: ByteArray): ByteArray? { - val token = pinToken ?: return null + fun computeAuthParam(message: ByteArray): ByteArray { + val token = pinToken ?: throw IllegalStateException("No pin token") - try { - val mac = Mac.getInstance("HmacSHA256") - mac.init(SecretKeySpec(token, "HmacSHA256")) - val hmacResult = mac.doFinal(message) - return hmacResult.copyOf(16) - } catch (e: Exception) { - return null - } + val mac = Mac.getInstance("HmacSHA256") + mac.init(SecretKeySpec(token, "HmacSHA256")) + val hmacResult = mac.doFinal(message) + return hmacResult.copyOf(16) } /**