SecItemCopyMatching всегда возвращает «не является допустимым элементом цепочки ключей» для сохраненного ключа EC

#ios #swift #keychain

#iOS #swift #связка ключей

Вопрос:

У меня есть функция, которая создает новый ключ в связке ключей iOS, используя этот метод:

 func initialize(_ keyTag: String) throws -> DeviceBindingParameters {
    let tag = keyTag.data(using: .utf8)!
    let attributes: [String: Any] =
            [kSecAttrKeyType       as String: kSecAttrKeyTypeECSECPrimeRandom,
             kSecAttrKeySizeInBits as String: 256,
             kSecPrivateKeyAttrs   as String: [
                kSecAttrIsPermanent    as String: true,
                kSecAttrLabel          as String: tag,
                kSecAttrApplicationTag as String: tag
             ]
            ]

    ... other stuff
}
  

И затем есть также функция, которая проверяет, присутствует ли этот ключ или нет:

 open func doesKeyExist(_ keyTag: String) -> Bool {
    let tag = keyTag.data(using: .utf8)!
    let query: [String: Any] = [
            kSecClass as String : kSecAttrKeyType,
            kSecAttrLabel as String : tag,
            kSecAttrApplicationTag as String: tag,
            kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
            kSecReturnRef as String: true
    ]
        
    var item: CFTypeRef?
    let status = SecItemCopyMatching(query as CFDictionary, amp;item)
    let errorDescription = SecCopyErrorMessageString(status,nil)
    print(errorDescription)
    return status == noErr
}
  

И я вызываю этот метод просто один за другим (для быстрого тестирования я вызываю это из AppDelegate.swift :

 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    do {
        try crypto.initialize("rohan-key")
        let keyStatus = try crypto.doesKeyExist("rohan-key")
            print("Key status: (keyStatus)")
    } catch {
        print("errors")
    }
  

И я всегда получаю этот вывод:

 Optional(The specified item does not appear to be a valid keychain item.)
Key status: false
  

Первое сообщение печатается при вызове состояния SecCopyErrorMessageString on SecItemCopyMatching . Кроме того, я очень уверен, что генерация ключа работает, потому что я использую ключ для подписи канонического сообщения, отправки его по проводам, а затем проверки этой подписи на серверной части на основе Java — так что эти части полностью в порядке. Я просто не уверен, почему элемент не сохраняется в хранилище ключей.

Ответ №1:

Вы допустили незначительную ошибку в kSecClass as String : kSecAttrKeyType . kSecAttrKeyType является ключом, указывающим тип ключа ( kSecAttrKeyTypeEC / kSecAttrKeyTypeECSECPrimeRandom / kSecAttrKeyTypeRSA ). Поэтому вы должны передать правильное kSecClass , которое для вас должно быть kSecClassKey .

Я хотел бы отметить, что время от времени вывод SecCopyErrorMessageString немного плохой. Всегда пытайтесь OSStatus также распечатать и использовать это в OSStatus. Что в этом случае не дало бы вам наибольших результатов, так как вернуло бы -50. Но комбинация этих двух идентифицирует их достаточно однозначно, чтобы определить ее так, как errSecNoSuchClass найдено здесь .

Комментарии:

1. Да. Похоже, что это так, и спасибо за ссылку на osstatus — это очень полезно!