iOS8 + KeychainItemWrapper от Apple приводит к сбою

Я копался в форумах Apple и ТАК для этой проблемы, но безрезультатно. Используя Apple KeychainItemWrapper (ARCified), пытаясь установить kSecAttrAccessible приписывать что-либо, кроме по умолчанию (kSecAttrAccessibleWhenUnlocked) приводит к ошибке подтверждения из SecItemUpdate, возвращающей ошибку.

KeychainItemWrapper *wrapper = [[KeyChainItemWrapper alloc] initWithIdentifier:kMyIdentifier accessGroup:nil];
[wrapper setObject:kMyServiceName forKey:(__bridge NSString*)kSecAttrService];
[wrapper setObject:kMyAccountToken forKey:(__bridge NSString*)kSecAttrAccount];
[wrapper setObject:(__bridge NSString*)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly forKey:(__bridge NSString*)kSecAttrAccessible];

Остальные наши обновления цепочки для ключей, кажется, проходят хорошо, но последняя строка приводит к:

*** Assertion failure in -[KeychainItemWrapper writeToKeychain], /Users/john.hammerlund/.../KeychainItemWrapper.m:299

Ошибка подтверждения связана с тем, что SecItemUpdate() возвращает состояние -50, что, по-видимому, является общей ошибкой "неверных параметров".

Сразу установка kSecAttrAccessible ключ не влияет, но установка его по умолчанию kSecAttrAccessibleWhenUnlocked смягчает проблему (но устраняет суть). Этот другой вопрос - единственная дополнительная информация, которую я нашел относительно iOS 8, вызывающей сбой KeychainItemWrapper. Построение на устройстве с iOS 7 или симулятор на iOS 7/8 устраняет проблему; он вспыхивает только на реальном устройстве с iOS 8.

Обновить

Вот широкий обзор словаря запросов:

{ accc = "<SecAccessControlRef: 0x1687cc70>"; acct = ...; agrp = ...; cdat = "2014-10-13 22:22:47 +0000"; desc = ""; gena = ...; labl = ""; mdat = "2014-10-13 22:34:16 +0000"; pdmn = cku; <-- kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly svce = ...; sync = 0; tomb = 0; "v_Data" = <>; }

и параметр attributeToUpdate:

{ accc = "<SecAccessControlRef: 0x1687cc70>"; acct = ...; agrp = ...; cdat = "2014-10-13 22:22:47 +0000"; desc = ""; gena = ...; labl = ""; mdat = "2014-10-13 22:34:16 +0000"; pdmn = ak; <-- kSecAttrAccessibleWhenUnlocked svce = ...; sync = 0; tomb = 0; "v_Data" = <>; }

Я подтвердил, что изменение других полей (например, kSecAttrService, kSecAttrAccount) одинаково влияет на соответствующие поля в словарях, но с ожидаемым состоянием 0.

3 ответа

Решение

У меня тоже была точная проблема. Дал мне:

Ошибка OSStatus -50 - конфликтующие атрибуты kSecAccess и kSecAccessControl

Сбой всем моим пользователям в магазине приложений сразу после их обновления.

Сделал так же, как Петр. Схватил данные, удалил элемент и вставил его как новый элемент вместо попытки обновить существующий.

Я думаю, это ошибка Apple.

Я открыл TSI, но они еще не связались со мной.

Насколько я понимаю, это происходит с пользователями, обновленными с iOS7 до iOS 8, где их первое приложение было скомпилировано с XCode для iOS7 (до выхода iOS 8), а затем на iOS8 обновлено до нового приложения, скомпилированного с XCode для iOS8,

У меня такая же проблема. Я закончил тестированием kSecAttrAccessibile и, если это было не то, что я хотел, я записал значение и атрибуты в цепочку для ключей в локальных переменных, сбросил цепочку для ключей, установил kSecAttrAccessible по желанию, а затем установил значение и атрибуты в цепочке для ключей в их исходные настройки.

Выстрел в темноте здесь:

Возможно, на устройстве iOS включена синхронизация iCloud, добавление элемента, который не зависит от конкретного устройства, а затем его создание ThisDeviceOnly приводит к ошибке. iOS8, возможно, также изменил поведение.

Можете ли вы попробовать изменить порядок атрибутов, которые установлены в связку ключей

KeychainItemWrapper *wrapper = [[KeyChainItemWrapper alloc] initWithIdentifier:kMyIdentifier accessGroup:nil];
[wrapper setObject:(__bridge NSString*)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly forKey:(__bridge NSString*)kSecAttrAccessible];
[wrapper setObject:kMyServiceName forKey:(__bridge NSString*)kSecAttrService];
[wrapper setObject:kMyAccountToken forKey:(__bridge NSString*)kSecAttrAccount];

Если это не помогает, вы должны изменить KeychainItemWrapper, чтобы выглядеть так

- (void)resetKeychainItem
{
    if (!keychainItemData)
    {
        keychainItemData = [[NSMutableDictionary alloc] init];
        [keychainItemData setObject:(__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly forKey:(__bridge id)kSecAttrAccessible];
    }
Другие вопросы по тегам