是否可以更新Keychain项的kSecAttrAccessible值?

时间:2023-01-12 18:05:09

Is it possible to update the value of the attribute kSecAttrAccessible of existing items in the Keychain? It seems that it cannot be changed after the item was added to the Keychain. The following steps back up my assumption.

是否可以更新Keychain中现有项的属性kSecAttrAccessible的值?项目被添加到钥匙串后似乎无法更改。以下步骤支持我的假设。

Add a new item to the Keychain:

将新项添加到钥匙串:

NSData *encodedIdentifier = [@"BUNDLE_IDENTIFIER" 
                             dataUsingEncoding:NSUTF8StringEncoding];
NSData *encodedPassword = [@"PASSWORD"
                           dataUsingEncoding:NSUTF8StringEncoding];

// Construct a Keychain item
NSDictionary *keychainItem = 
    [NSDictionary dictionaryWithObjectsAndKeys:
        kSecClassGenericPassword, kSecClass,
        encodedIdentifier, kSecAttrGeneric,
        encodedIdentifier, kSecAttrService,
        @"USERNAME", kSecAttrAccount,
        kSecAttrAccessibleWhenUnlocked, kSecAttrAccessible,
        encodedPassword, kSecValueData
        nil];

// Add item to Keychain
OSStatus addItemStatus = SecItemAdd((CFDictionaryRef)keychainItem, NULL);

At a later time, change the attribute kSecAttrAccessible from kSecAttrAccessibleWhenUnlocked to kSecAttrAccessibleAfterFirstUnlock:

稍后,将属性kSecAttrAccessible从kSecAttrAccessibleWhenUnlocked更改为kSecAttrAccessibleAfterFirstUnlock:

NSData *encodedIdentifier = [@"BUNDLE_IDENTIFIER" 
                             dataUsingEncoding:NSUTF8StringEncoding];

NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys:
                       kSecClassGenericPassword, kSecClass,
                       encodedIdentifier, kSecAttrGeneric,
                       encodedIdentifier, kSecAttrService,
                       nil];

NSDictionary *updatedAttributes = 
    [NSDictionary dictionaryWithObject:kSecAttrAccessibleAfterFirstUnlock 
                                forKey:kSecAttrAccessible];

OSStatus updateItemStatus = SecItemUpdate((CFDictionaryRef)query, 
                                          (CFDictionaryRef)updatedAttributes);

The problem with this approach is that updateItemStatus always results in the status errSecUnimplemented.

这种方法的问题是updateItemStatus总是导致errSecUnimplemented状态。

I think it should be possible to update the value of kSecAttrAccessible because requirements of applications change. What if an application added ten items to the Keychain in the past without specifying the protection class with kSecAttrAccessible. The Keychain implicitly assigns new items the value kSecAttrAccessibleWhenUnlocked if the protection class is not set explicitly by the developer. Later, the developer needs to change the protection class to kSecAttrAccessibleAfterFirstUnlock because the application must access it in the background (Multitasking). How can the developer accomplish that?

我认为应该可以更新kSecAttrAccessible的值,因为应用程序的需求会发生变化。如果应用程序过去在Keychain中添加了10个项目而未使用kSecAttrAccessible指定保护类,该怎么办?如果开发人员未明确设置保护类,则Keychain会隐式地为新项目分配值kSecAttrAccessibleWhenUnlocked。稍后,开发人员需要将保护类更改为kSecAttrAccessibleAfterFirstUnlock,因为应用程序必须在后台访问它(多任务处理)。开发人员如何实现这一目标?

There is already a thread in the Apple Developer Forums, but it has not yielded an answer yet: https://devforums.apple.com/thread/87646?tstart=0

Apple开发者论坛中已有一个主题,但尚未得出答案:https://devforums.apple.com/thread/87646?tstart = 0

2 个解决方案

#1


18  

After opening a support incident at Apple Developer Technical Support (ADTS), I received a reply that answers this question. SecItemUpdate() requires the Keychain item's data via the attribute kSecValueData to perform the update of the attribute kSecAttrAccessible. According to ADTS, this constraint is currently not documented in the reference documentation.

在Apple开发人员技术支持(ADTS)上打开支持事件后,我收到了回复此问题的回复。 SecItemUpdate()通过属性kSecValueData需要Keychain项的数据来执行属性kSecAttrAccessible的更新。根据ADTS,此约束目前未在参考文档中记录。

NSData *encodedIdentifier = [@"BUNDLE_IDENTIFIER" 
                             dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys:
                       kSecClassGenericPassword, kSecClass,
                       encodedIdentifier, kSecAttrGeneric,
                       encodedIdentifier, kSecAttrService,
                       nil];

// Obtain the Keychain item's data via SecItemCopyMatching()
NSData *itemData = ...;

NSDictionary *updatedAttributes = 
    [NSDictionary dictionaryWithObjectsAndKeys:
        kSecAttrAccessibleAfterFirstUnlock, kSecAttrAccessible,
        (CFDataRef)itemData, kSecValueData,
        nil];

OSStatus updateItemStatus = SecItemUpdate((CFDictionaryRef)query, 
                                          (CFDictionaryRef)updatedAttributes);

// updateItemStatus should have the value errSecSuccess

#2


1  

I was unable to get the other answer to work. I ended up testing kSecAttrAccessibile and if it wasn't what I wanted I recorded the value and attributes in the keychain in local variables, reset the keychain, set kSecAttrAccessible as desired and then set the value and attributes in the keychain to their original settings.

我无法得到其他工作的答案。我最后测试了kSecAttrAccessibile,如果它不是我想要的,我在局部变量的keychain中记录了值和属性,重置了keychain,根据需要设置了kSecAttrAccessible,然后将keychain中的值和属性设置为原始设置。

#1


18  

After opening a support incident at Apple Developer Technical Support (ADTS), I received a reply that answers this question. SecItemUpdate() requires the Keychain item's data via the attribute kSecValueData to perform the update of the attribute kSecAttrAccessible. According to ADTS, this constraint is currently not documented in the reference documentation.

在Apple开发人员技术支持(ADTS)上打开支持事件后,我收到了回复此问题的回复。 SecItemUpdate()通过属性kSecValueData需要Keychain项的数据来执行属性kSecAttrAccessible的更新。根据ADTS,此约束目前未在参考文档中记录。

NSData *encodedIdentifier = [@"BUNDLE_IDENTIFIER" 
                             dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys:
                       kSecClassGenericPassword, kSecClass,
                       encodedIdentifier, kSecAttrGeneric,
                       encodedIdentifier, kSecAttrService,
                       nil];

// Obtain the Keychain item's data via SecItemCopyMatching()
NSData *itemData = ...;

NSDictionary *updatedAttributes = 
    [NSDictionary dictionaryWithObjectsAndKeys:
        kSecAttrAccessibleAfterFirstUnlock, kSecAttrAccessible,
        (CFDataRef)itemData, kSecValueData,
        nil];

OSStatus updateItemStatus = SecItemUpdate((CFDictionaryRef)query, 
                                          (CFDictionaryRef)updatedAttributes);

// updateItemStatus should have the value errSecSuccess

#2


1  

I was unable to get the other answer to work. I ended up testing kSecAttrAccessibile and if it wasn't what I wanted I recorded the value and attributes in the keychain in local variables, reset the keychain, set kSecAttrAccessible as desired and then set the value and attributes in the keychain to their original settings.

我无法得到其他工作的答案。我最后测试了kSecAttrAccessibile,如果它不是我想要的,我在局部变量的keychain中记录了值和属性,重置了keychain,根据需要设置了kSecAttrAccessible,然后将keychain中的值和属性设置为原始设置。