Связка ключей iOS: SecItemUpdate возвращает -50 (paramErr) при обновлении kSecAttrAccessible

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

Сначала я пытаюсь найти элемент, чтобы убедиться, что мой словарь запросов хорош:

sanityCheck = SecItemCopyMatching((__bridge CFDictionaryRef)(queryPrivateKey), (void *)&privateKeyRef);

Эта строка успешно находит мне искомый элемент (код возврата 0).

Затем я обновляю атрибут kSecAttrAccessible, используя тот же запрос:

if (sanityCheck == noErr && privateKeyRef != nil) {
    // found it, update accessibility
    NSMutableDictionary *updatedAttributes = [[NSMutableDictionary alloc] init];
    updatedAttributes[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAlways;
    OSStatus updateItemStatus = SecItemUpdate((__bridge CFDictionaryRef)queryPrivateKey, (__bridge CFDictionaryRef)updatedAttributes);
}

На данный момент updateItemStatus равен -50 (paramErr).

Я просмотрел этот поток: Возможно ли обновить значение kSecAttrAccessible элемента связки ключей? Однако моя проблема отличается. Он возвращает -50, даже если я добавляю kSecValueData в свой updatedAttributes. Кроме того, в документации также указано, что добавлять kSecValueData нужно только для iOS 4 и более ранних версий. Я поддерживаю iOS 7 и выше, так что это не должно быть моей проблемой.

Может ли кто-нибудь указать, что мне здесь не хватает? Большое спасибо.


person SeaJelly    schedule 19.05.2015    source источник


Ответы (1)


Тот факт, что запрос может успешно найти элемент связки ключей с помощью SecItemCopyMatching, не означает, что тот же запрос можно использовать для обновления элемента связки ключей.

Я использую следующий запрос для поиска элемента:

[queryPrivateKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
[queryPrivateKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
[queryPrivateKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
[queryPrivateKey setObject:[EncryptionHelper privateKeyTag:JWT_KEYPAIR_TAG] forKey:(__bridge id<NSCopying>)(kSecAttrApplicationTag)];

sanityCheck = SecItemCopyMatching((__bridge CFDictionaryRef)(queryPrivateKey), (void *)&privateKeyef);

Однако, чтобы использовать этот запрос для обновления элемента, мне сначала нужно было сделать:

[queryPrivateKey removeObjectForKey:(__bridge id)kSecReturnRef];

Затем я могу обновить:

OSStatus updateItemStatus = SecItemUpdate((__bridge CFDictionaryRef)queryPrivateKey,(__bridge CFDictionaryRef)updatedAttributes);

Очевидно, что kSecReturnRef не является приемлемым ключом в словаре запросов SecItemUpdate. Мне не удалось найти список допустимых ключей запроса SecItemUpdate в документации Apple. Из документации SecItemUpdate, кажется, что только эти ключи допустимы, но это неправильный список, поскольку Я ожидаю, что в списке будут такие ключи, как kSecClass и т. д. Если у кого-то есть обновленная ссылка на документ, пожалуйста, поделитесь ею, а пока мне нужно лишь несколько проб и ошибок, чтобы выяснить, какие ключи приемлемы для SecItemUpdate.

После того, как элемент был найден, есть еще одна сложность с обновлением kSecAttrAccessible: вы не можете обновить более высокий параметр безопасности, такой как kSecAttrAccessibleWhenUnlocked, до более низкого параметра, такого как kSecAttrAccessibleAlways, когда телефон заблокирован из соображений безопасности, поэтому миграция должна произойти, когда телефон разблокирован. Хорошим местом для миграции является возобновление работы приложения на переднем плане, поскольку устройство должно быть в разблокированном состоянии, когда приложение находится на переднем плане.

person SeaJelly    schedule 26.05.2015
comment
У меня точно такая же проблема @SeaJelly. Я использую Apple Keychain Wrapper, который использует kSecAttrAccessible по умолчанию. И я хочу обновить его до kSecAttrAccessibleWhenUnlocked. По какой-то причине я не могу обновить этот атрибут. Удалось сделать это успешно? - person jonypz; 28.05.2015
comment
@jonypz Да, теперь я могу успешно обновить свою доступность, удалив пару ключей в моем запросе (первый аргумент SecItemUpdate), как указано выше. Но к вашему сведению, прямо сейчас значение по умолчанию уже kSecAttrAccessibleWhenUnlocked. Раньше это было kSecAttrAccessibleAlways, но это уже не так. В какой-то момент они изменили значение по умолчанию на kSecAttrAccessibleWhenUnlocked. В моем случае все наоборот, я хочу изменить его с разблокированного (по умолчанию) на всегда. - person SeaJelly; 28.05.2015
comment
Извините, я имел в виду kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly. Но вы удаляете ключ kSecReturnRef. Разве вы не должны удалить kSecAttrAccessible и установить его обратно с нужным вам параметром? - person jonypz; 28.05.2015
comment
@jonypz Для первого аргумента вам не нужно, чтобы kSecAttrAccessible присутствовал в запросе на поиск. У меня нет kSecAttrAccessible в запросе. У меня также нет kSecReturnRef — я удалил его, потому что иначе поиск не удастся. Затем, с правильным запросом, я помещаю kSecAttrAccessible во второй аргумент (аргумент обновленных атрибутов), и это делает обновление для меня. В основном вы хотите kSecAttrAccessible только во втором аргументе, но не в первом аргументе. - person SeaJelly; 28.05.2015
comment
понятно. Я попытаюсь это сделать и дам вам знать, как это происходит. Спасибо - person jonypz; 28.05.2015
comment
не работал. Несмотря на то, что я могу выполнить запрос, я не могу выполнить обновление до kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly. OSStatus выходит как -50. - person jonypz; 28.05.2015
comment
SecItemUpdate() ничего не возвращает, он принимает запрос о том, что нужно обновить, и описание обновления, как его обновить, и единственными выходными значениями является код состояния. Таким образом, указание любого kSecReturn... не имеет смысла, поскольку как это значение будет возвращено? - person Mecki; 08.09.2017