- По умолчанию вы устанавливаете пин-код для конкретного приложения.
- После этого пользователь может включить биометрию (Face ID или Touch ID) для быстрой аутентификации.
- После этого пользователь может подписать сообщение, используя свой закрытый ключ, хранящийся в Secure Enclave. либо с помощью биометрии, либо пользователь может вернуться к своему PIN-коду для конкретного приложения (либо по выбору, либо в случае отмены или невозможности распознания, например).
Флаг .applicationPassword для SecAccessControlCreateFlags показался разумным вариантом, позволяющим разрешить использование пароля, определенного приложением. использовал. Кроме того, набор возможных флагов также содержит ограничения, такие как devicePasscode и biometryCurrentSet, для установки ограничений доступа, которые можно даже комбинировать с помощью союзов. Следует отметить, что applicationPassword является не ограничением, а «опцией» согласно документации. Также не очень хорошо документировано, что на самом деле делает этот флаг. Тем не менее, я попробовал следующее:
Код: Выделить всё
let flags1: SecAccessControlCreateFlags = [.privateKeyUsage,
.biometryCurrentSet, .or, .applicationPassword]
let flags2: SecAccessControlCreateFlags = [.privateKeyUsage,
.biometryCurrentSet, .applicationPassword]
let access1 = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
flags1,
&error)
let access2 = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
flags2,
&error)
Я попробовал программно. предоставление пароля приложения с помощью LAContext.setCredential, и это работает нормально, поскольку запрос пароля приложения больше не будет отображаться, но iOS по-прежнему всегда будет запрашивать биометрические данные (даже при использовании флага .or) ). Таким образом, похоже, что флаг .or не работает так, как я надеялся, вместе с .applicationPassword. Тем не менее, эти политики контроля доступа, похоже, требуют, чтобы и биометрические данные, и пароль приложения передавались, что является хорошей возможностью, но не совсем тем, что я искал.
Я также пытался запретить соответствующие запросы, такие как Face ID приглашение не отображается с помощью LAContext.interactionNotAllowed, но это также не работает из-за флагов контроля доступа.
Базовая настройка
Для тестируя это, у меня есть простой Приложение iOS настроено со следующими функциями, полученными из документации Secure Enclave:
Код: Выделить всё
func getAccessControl() -> SecAccessControl {
var access: SecAccessControl?
access = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
[.privateKeyUsage,
.biometryCurrentSet,
.or,
.applicationPassword],
nil)!
return access
}
func generatePrivateKey() throws -> SecKey {
let context = LAContext()
context.setCredential("pwd123".data(using: .utf8), type: .applicationPassword)
let attributes: NSDictionary = [
kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
kSecAttrKeySizeInBits: 256,
kSecAttrTokenID: kSecAttrTokenIDSecureEnclave,
kSecUseAuthenticationContext as String: context,
kSecAttrLabel: "label-for-reference",
kSecClass: kSecClassKey,
kSecPrivateKeyAttrs: [
kSecAttrIsPermanent: true,
kSecAttrApplicationTag: "tag-for-reference",
kSecAttrAccessControl: getAccessControl(),
]
]
var error: Unmanaged?
guard let privateKey = SecKeyCreateRandomKey(attributes, &error) else {
throw error!.takeRetainedValue() as Error
}
return privateKey
}
func retrieveKey(context: LAContext? = nil) -> SecKey? {
var attributes: [String: Any] = [
kSecClass as String: kSecClassKey,
kSecAttrLabel as String: "label-for-reference",
kSecMatchLimit as String: kSecMatchLimitOne,
kSecReturnRef as String: true,
]
if let context = context {
attributes[kSecUseAuthenticationContext as String] = context
}
var item: CFTypeRef?
let res = SecItemCopyMatching(attributes as CFDictionary, &item)
if (res == errSecSuccess) {
return (item as! SecKey)
} else {
return nil
}
}
func sign(data: String, key: SecKey) throws -> Data? {
if (SecKeyIsAlgorithmSupported(key, .sign, .ecdsaSignatureMessageX962SHA256)) {
var error: Unmanaged?
guard let signature = SecKeyCreateSignature(key,
.ecdsaSignatureMessageX962SHA256,
data.data(using: .utf8)! as CFData,
&error) as Data? else {
throw error!.takeRetainedValue() as Error
}
return signature
}
return nil
}
Код: Выделить всё
let privateKey = generatePrivateKey()
let context = LAContext()
context.setCredential("pwd123".data(using: .utf8), type: .applicationPassword)
let retrievedKey = retrieveKey(context)
var signedMessage: Data?
try signedMessage = sign(data: "abc", key: retrievedKey!))
Я хотел бы узнать, не упускаю ли я что-то в этой документации (в частности, по контролю доступа элементов связки ключей [безопасного анклава]), или, альтернативно, если есть особый обходной путь, позволяющий сделать эту работу. Например, я также подумал о том, чтобы объединить параметры доступа, например. Face ID --unlocks--> Код доступа к приложению --unlocks--> Закрытый ключ, чтобы код доступа к приложению мог быть предоставлен либо с помощью Face ID, либо непосредственно пользователем. Однако это приведет к загрузке пароля приложения в память (что в любом случае может не быть проблемой, если пользователь уже вводит свой пин-код в настраиваемом пользовательском интерфейсе). Как обычно решают эту проблему приложения со схожими функциями?
Подробнее здесь: https://stackoverflow.com/questions/740 ... to-authent
Мобильная версия