Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to update a Keychain item's kSecAttrAccessible value?

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.

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:

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.

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?

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

like image 380
Manuel Binna Avatar asked Mar 20 '11 14:03

Manuel Binna


People also ask

What is key value and attribute?

A key whose value is a string indicating the item's service. A key whose value indicates the item's user-defined attributes. A key whose value is a string indicating the item's security domain.

How do I delete items from my Iphone keychain?

You can't remove a keychain item from iOS device. The keychain is shared between applications, so another app could be using the same credentials. You should just leave the info alone when your app is removed. The keychain will persist even after the app is removed.


2 Answers

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.

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 
like image 104
Manuel Binna Avatar answered Sep 24 '22 06:09

Manuel Binna


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.

like image 41
Peter B. Kramer Avatar answered Sep 21 '22 06:09

Peter B. Kramer