更改钥匙串中 kSecAttrAccessible 的值是否可行?

27

更新已经存在于Keychain中的项目的属性kSecAttrAccessible的值是否可能?看起来似乎在将项目添加到Keychain后无法更改它。以下步骤支持了我的想法。

向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);

稍后将属性 kSecAttrAccessiblekSecAttrAccessibleWhenUnlocked 更改为 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);
这种方法的问题在于,updateItemStatus 总是导致状态 errSecUnimplemented
我认为应该可以更新 kSecAttrAccessible 的值,因为应用程序的要求会发生变化。如果一个应用程序在过去添加了十个项目到钥匙串中,而没有使用 kSecAttrAccessible 指定保护级别,那么如果开发人员没有明确设置保护级别,则钥匙串会隐式地将新项目分配给值为 kSecAttrAccessibleWhenUnlocked。稍后,开发人员需要将保护级别更改为 kSecAttrAccessibleAfterFirstUnlock,因为应用程序必须在后台(多任务)中访问它。开发人员如何才能实现这一点?
Apple Developer论坛中已经有了一个主题,但还没有得到答案: https://devforums.apple.com/thread/87646?tstart=0
2个回答

25

我在苹果开发者技术支持(ADTS)提交了一个支持事件后,收到了回复,回答了这个问题。 SecItemUpdate() 需要通过属性 kSecValueData 获取密钥链项的数据,以执行属性 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

1
现在已经记录,需要在iOS 4及更早版本中使用。 - Nikolai Ruhe
如果您正在使用RSA密钥对,请确保对两个密钥都执行此操作。 - Patrick Goley
@PatrickGoley 我需要帮助在设备锁定时读取我的私钥,您有任何想法应该如何设置kSecAttrAccessible来生成密钥对吗?我应该如何设置kSecAttrAccessible来读取它?我的问题只是针对密钥对。谢谢。 - Mo Farhand
这个不起作用。有人有解决方案吗? - iqra

1

我无法让另一个答案正常工作。最终,我测试了kSecAttrAccessibile,如果不是我想要的,就记录了密钥链中的值和属性到本地变量中,重置了密钥链,设置所需的kSecAttrAccessible,然后将值和属性设置回密钥链的原始设置。


你不碰巧有这个的代码片段吗?我在尝试让它工作时遇到了一些问题。 - Patrick Goley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接