将 SecAccessControl 与密码和生物识别一起使用时,钥匙串 SecItemAdd 失败
Posted
技术标签:
【中文标题】将 SecAccessControl 与密码和生物识别一起使用时,钥匙串 SecItemAdd 失败【英文标题】:Keychain SecItemAdd fails when using SecAccessControl with Passcode & Biometry 【发布时间】:2021-03-11 07:05:07 【问题描述】:我目前能够重现一个错误,其中SecItemAdd
在设置了密码但尚未在设备上设置生物识别(但通常可用)的设备上进行测试时失败。
错误:
OSStatus 给出-25293
,好像是errSecAuthFailed
。
我想要实现的目标:
我想以设备密码作为最低安全要求将项目存储到钥匙串中。此外,如果启用了 Biometry,我希望允许用户使用它来保护和访问该项目。与.userPresence
相比,我想阻止在生物特征更改 时访问该项目,因此标志中的.biometryCurrentSet
似乎是正确的选择。
因此,对于保护级别,失败的组合是 kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
,SecAccessControlCreateFlags
是 [.biometryCurrentSet, .or, .devicePasscode]
。
示例代码(重现的最小演示):
import SwiftUI
struct ContentView: View
func keychainTest()
var attributes: [String: Any] = [kSecValueData as String: "abc".data(using: .utf8)!]
var error: Unmanaged<CFError>?
defer
error?.release()
guard let accessControl = SecAccessControlCreateWithFlags(
nil,
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly as CFString,
[.biometryCurrentSet, .or, .devicePasscode], // this fails when Device has Biometry deactivated
&error
) else
debugPrint("Error creating Access Control")
return
attributes[kSecAttrAccessControl as String] = accessControl
// try adding new keychain item
attributes[kSecClass as String] = kSecClassGenericPassword
attributes[kSecAttrAccount as String] = "keychaintest.mybundle.com.keyid1234"
let saveStatus = SecItemAdd(attributes as CFDictionary, nil)
if saveStatus != errSecSuccess
debugPrint("Error Saving")
var body: some View
Text("Hello, world!")
.padding()
.onAppear
self.keychainTest()
注意:最小的演示是在 SwiftUI 中创建的,但最初的失败源来自 UIKit 项目,这在此处无关紧要。 FaceID 隐私字符串在Info.plist
中设置。
只要我使用[.userPresence]
(相当于[.biometryAny, .or, .devicePasscode]
)而不是想要的标志,SecItemAdd
就会成功。
我错过了什么?
编辑:当然存在具有相同键的上一个项目。我每次尝试都会更改它并使用新的测试设备(ios 14.4)。
编辑 2:这似乎相关。 IOS not able to create privatekey if only devicecode is set on device?。不一样(这里是SecItemAdd
),但访问控制也创建了一个有效的引用,但后来 Key 方法失败了。
另外还转储了 saveStatus failed 分支中的属性:
(lldb) po attributes
▿ 4 elements
▿ 0 : 2 elements
- key : "v_Data"
▿ value : 3 bytes
- count : 3
▿ pointer : 0x000000016b282d50
- pointerValue : 6092762448
▿ bytes : 3 elements
- 0 : 97
- 1 : 98
- 2 : 99
▿ 1 : 2 elements
- key : "accc"
- value : <SecAccessControlRef: akpu;od(pkofn(1)cup(true)cbio(pbioc()pbioh()));odel(true);oe(true)>
▿ 2 : 2 elements
- key : "acct"
- value : "keychaintest.mybundle.com.keyid1234.13"
▿ 3 : 2 elements
- key : "class"
- value : genp
【问题讨论】:
【参考方案1】:归档为雷达 FB9039075。
一位队友(https://***.com/users/2451589/julien-klindt,谢谢!)之后收到了来自 Apple(使用 DTS)的反馈:
这里的
.or
操作符指的是读操作。也就是说,要读取项目,系统必须能够满足一个或多个指定的约束。但是,在您的情况下,在 add 操作中事情失败了。这里.biometryCurrentSet
的存在表明钥匙串必须用当前的生物特征集标记该项目,这不可能工作,因为当前没有配置生物特征。
所以这是设计的。如果需要,Apple 建议为所描述的行为创建功能请求。
就解决方法而言,捕获此错误然后询问本地身份验证是否启用了生物识别似乎是合理的。如果不是,您可以退回到
.devicePasscode
。
如果不需要对生物特征进行更改使项目无效,我建议改用.userPresence
。
【讨论】:
以上是关于将 SecAccessControl 与密码和生物识别一起使用时,钥匙串 SecItemAdd 失败的主要内容,如果未能解决你的问题,请参考以下文章