Consolidate PIN and UV parameters in FIDO commands

This commit is contained in:
mimi89999
2026-03-27 00:03:20 +01:00
parent 5963329f45
commit 9a98e79c76
3 changed files with 50 additions and 45 deletions
@@ -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 {
@@ -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<Pair<String, Int>>,
excludeList: List<ByteArray>? = null,
requireResidentKey: Boolean = true,
requireUserVerification: Boolean = true,
uvMode: UvMode = UvMode.None,
extensions: Map<String, Any>? = 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<ByteArray>? = 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
}
}
}
@@ -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)
}
/**