diff --git a/play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/transport/screenlock/ScreenLockCredentialStore.kt b/play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/transport/screenlock/ScreenLockCredentialStore.kt index 384fafcc16..fa536be821 100644 --- a/play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/transport/screenlock/ScreenLockCredentialStore.kt +++ b/play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/transport/screenlock/ScreenLockCredentialStore.kt @@ -10,6 +10,7 @@ import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteOpenHelper import android.os.Build import android.security.keystore.KeyGenParameterSpec +import android.security.keystore.KeyPermanentlyInvalidatedException import android.security.keystore.KeyProperties import android.util.Base64 import android.util.Log @@ -20,6 +21,7 @@ import java.security.cert.Certificate import java.security.spec.ECGenParameterSpec import kotlin.random.Random +@RequiresApi(23) class ScreenLockCredentialStore(val context: Context) { private val keyStore by lazy { KeyStore.getInstance("AndroidKeyStore").apply { load(null) } } @@ -51,10 +53,15 @@ class ScreenLockCredentialStore(val context: Context) { keyStore.getCertificateChain(getAlias(rpId, keyId)) fun getSignature(rpId: String, keyId: ByteArray): Signature? { - val privateKey = getPrivateKey(rpId, keyId) ?: return null - val signature = Signature.getInstance("SHA256withECDSA") - signature.initSign(privateKey) - return signature + try { + val privateKey = getPrivateKey(rpId, keyId) ?: return null + val signature = Signature.getInstance("SHA256withECDSA") + signature.initSign(privateKey) + return signature + } catch (e: KeyPermanentlyInvalidatedException) { + keyStore.deleteEntry(getAlias(rpId, keyId)) + throw e + } } fun containsKey(rpId: String, keyId: ByteArray): Boolean = keyStore.containsAlias(getAlias(rpId, keyId)) diff --git a/play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/ui/AuthenticatorActivity.kt b/play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/ui/AuthenticatorActivity.kt index a5c06801bb..e894e344f9 100644 --- a/play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/ui/AuthenticatorActivity.kt +++ b/play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/ui/AuthenticatorActivity.kt @@ -122,7 +122,7 @@ class AuthenticatorActivity : AppCompatActivity(), TransportHandlerCallback { } @RequiresApi(24) - suspend fun handleRequest(options: RequestOptions) { + suspend fun handleRequest(options: RequestOptions, allowInstant: Boolean = true) { try { val facetId = getFacetId(this, options, callerPackage) options.checkIsValid(this, facetId, callerPackage) @@ -135,10 +135,10 @@ class AuthenticatorActivity : AppCompatActivity(), TransportHandlerCallback { Log.d(TAG, "facetId=$facetId, appName=$appName") // Check if we can directly open screen lock handling - if (!requiresPrivilege) { + if (!requiresPrivilege && allowInstant) { val instantTransport = transportHandlers.firstOrNull { it.isSupported && it.shouldBeUsedInstantly(options) } if (instantTransport != null && instantTransport.transport in INSTANT_SUPPORTED_TRANSPORTS) { - startTransportHandling(instantTransport.transport) + startTransportHandling(instantTransport.transport, true) return } } @@ -250,10 +250,18 @@ class AuthenticatorActivity : AppCompatActivity(), TransportHandlerCallback { return shouldStartTransportInstantly(SCREEN_LOCK) } - fun startTransportHandling(transport: Transport): Job = lifecycleScope.launchWhenResumed { + @RequiresApi(24) + fun startTransportHandling(transport: Transport, instant: Boolean = false): Job = lifecycleScope.launchWhenResumed { val options = options ?: return@launchWhenResumed try { finishWithSuccessResponse(getTransportHandler(transport)!!.start(options, callerPackage), transport) + } catch (e: SecurityException) { + Log.w(TAG, e) + if (instant) { + handleRequest(options, false) + } else { + finishWithError(SECURITY_ERR, e.message ?: e.javaClass.simpleName) + } } catch (e: CancellationException) { Log.w(TAG, e) // Ignoring cancellation here