diff --git a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/passkey/PasskeyProviderService.kt b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/passkey/PasskeyProviderService.kt index d766f54a1..d1e7f5871 100644 --- a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/passkey/PasskeyProviderService.kt +++ b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/passkey/PasskeyProviderService.kt @@ -343,14 +343,17 @@ class PasskeyProviderService : CredentialProviderService() { private fun MutableList.addPendingIntentCreationNewEntry( accountName: String, - searchInfo: SearchInfo? + searchInfo: SearchInfo?, + userVerification: UserVerificationRequirement ) { Log.d(TAG, "Add pending intent for registration in opened database to create new item") // TODO add a setting to directly store in a specific group PasskeyLauncherActivity.getPendingIntent( context = applicationContext, specialMode = SpecialMode.REGISTRATION, - searchInfo = searchInfo + searchInfo = searchInfo, + userVerification = userVerification, + userVerifiedWithAuth = false )?.let { pendingIntent -> this.add( CreateEntry( @@ -379,6 +382,7 @@ class PasskeyProviderService : CredentialProviderService() { ) val relyingPartyId = publicKeyCredentialCreationOptions.relyingPartyEntity.id val searchInfo = buildPasskeySearchInfo(relyingPartyId) + val userVerification = publicKeyCredentialCreationOptions.authenticatorSelection.userVerification Log.d(TAG, "Build passkey search for relying party $relyingPartyId") SearchHelper.checkAutoSearchInfo( context = this, @@ -389,7 +393,11 @@ class PasskeyProviderService : CredentialProviderService() { throw RegisterInReadOnlyDatabaseException() } else { // To create a new entry - createEntries.addPendingIntentCreationNewEntry(accountName, searchInfo) + createEntries.addPendingIntentCreationNewEntry( + accountName = accountName, + searchInfo = searchInfo, + userVerification = userVerification + ) /* TODO Overwrite // To select an existing entry and permit an overwrite Log.w(TAG, "Passkey already registered") @@ -420,7 +428,11 @@ class PasskeyProviderService : CredentialProviderService() { if (database.isReadOnly) { throw RegisterInReadOnlyDatabaseException() } else { - createEntries.addPendingIntentCreationNewEntry(accountName, searchInfo) + createEntries.addPendingIntentCreationNewEntry( + accountName = accountName, + searchInfo = searchInfo, + userVerification = userVerification + ) } callback(createEntries) }, @@ -429,7 +441,8 @@ class PasskeyProviderService : CredentialProviderService() { Log.d(TAG, "Add pending intent for passkey registration in closed database") PasskeyLauncherActivity.getPendingIntent( context = applicationContext, - specialMode = SpecialMode.REGISTRATION + specialMode = SpecialMode.REGISTRATION, + userVerifiedWithAuth = true )?.let { pendingIntent -> createEntries.add( CreateEntry( diff --git a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/passkey/data/FidoDataTypes.kt b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/passkey/data/FidoDataTypes.kt index 0fc2b2a65..c6c61f904 100644 --- a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/passkey/data/FidoDataTypes.kt +++ b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/passkey/data/FidoDataTypes.kt @@ -148,11 +148,12 @@ data class PublicKeyCredentialDescriptor( } } +// https://www.w3.org/TR/webauthn-3/#dictdef-authenticatorselectioncriteria data class AuthenticatorSelectionCriteria( val authenticatorAttachment: String? = null, val residentKey: ResidentKeyRequirement? = null, val requireResidentKey: Boolean?, - val userVerification: UserVerificationRequirement? = UserVerificationRequirement.PREFERRED + val userVerification: UserVerificationRequirement = UserVerificationRequirement.PREFERRED ) { companion object { fun JSONObject.getAuthenticatorSelectionCriteria( @@ -166,7 +167,9 @@ data class AuthenticatorSelectionCriteria( ResidentKeyRequirement.fromString(authenticatorSelection.getString("residentKey")) else null val requireResidentKey = authenticatorSelection.optBoolean("requireResidentKey", false) - val userVerification = UserVerificationRequirement.fromString(authenticatorSelection.optString("userVerification", "preferred")) + val userVerification = UserVerificationRequirement + .fromString(authenticatorSelection.optString("userVerification", "preferred")) + ?: UserVerificationRequirement.PREFERRED // https://www.w3.org/TR/webauthn-3/#enumdef-residentkeyrequirement if (residentKey == null) { residentKey = if (requireResidentKey) { @@ -195,7 +198,9 @@ enum class ResidentKeyRequirement(val value: String) { } companion object { fun fromString(value: String): ResidentKeyRequirement? { - return ResidentKeyRequirement.entries.firstOrNull { it.value == value } + return ResidentKeyRequirement.entries.firstOrNull { + it.value.equals(other = value, ignoreCase = true) + } } } } @@ -210,7 +215,9 @@ enum class UserVerificationRequirement(val value: String) { } companion object { fun fromString(value: String): UserVerificationRequirement? { - return UserVerificationRequirement.entries.firstOrNull { it.value == value } + return UserVerificationRequirement.entries.firstOrNull { + it.value.equals(other = value, ignoreCase = true) + } } } } \ No newline at end of file diff --git a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/passkey/util/PasskeyHelper.kt b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/passkey/util/PasskeyHelper.kt index d3c322d7e..0f8ed2d3d 100644 --- a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/passkey/util/PasskeyHelper.kt +++ b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/passkey/util/PasskeyHelper.kt @@ -557,6 +557,7 @@ object PasskeyHelper { */ fun buildCreatePublicKeyCredentialResponse( publicKeyCredentialCreationParameters: PublicKeyCredentialCreationParameters, + userVerified: Boolean, backupEligibility: Boolean, backupState: Boolean ): CreatePublicKeyCredentialResponse { @@ -574,7 +575,7 @@ object PasskeyHelper { keyTypeId = keyTypeId ) ?: mapOf()), userPresent = true, - userVerified = true, + userVerified = userVerified, backupEligibility = backupEligibility, backupState = backupState, publicKeyTypeId = keyTypeId, diff --git a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/viewmodel/PasskeyLauncherViewModel.kt b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/viewmodel/PasskeyLauncherViewModel.kt index 825823b90..e3ec69f0e 100644 --- a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/viewmodel/PasskeyLauncherViewModel.kt +++ b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/viewmodel/PasskeyLauncherViewModel.kt @@ -525,6 +525,7 @@ class PasskeyLauncherViewModel(application: Application): CredentialLauncherView intent = responseIntent, response = buildCreatePublicKeyCredentialResponse( publicKeyCredentialCreationParameters = it, + userVerified = mUserVerified, backupEligibility = passkey?.backupEligibility ?: mBackupEligibility, backupState = passkey?.backupState