iosobjective-ckeychainsecurity-framework

Update Keychain kSecAttrAccessible with SecItemUpdate returns -50


I'm trying to update the kSecAttrAccessible of my Keychain item based on mbinna question's.

The problem is that the following code returns -50 for the updateItemStatus variable. I took I look in a similar question about it then removed the kSecReturnRef attribute from my query (newQuery), but its still not working and returning -50, which means "One or more parameters passed to a function were not valid."

What am I doing wrong?

NSString *privateKeyAttrTag = @"mykeytag";

NSDictionary *getQuery = [NSDictionary dictionaryWithObjectsAndKeys:
        kSecClassKey, kSecClass, 
        privateKeyAttrTag, kSecAttrApplicationTag, 
        kSecAttrKeyTypeRSA, kSecAttrKeyType, 
        @YES, kSecReturnRef, 
        kSecAttrAccessibleWhenUnlocked, kSecAttrAccessible, nil];

CFTypeRef dataTypeRef = NULL;
OSStatus status = SecItemCopyMatching(
    (__bridge CFDictionaryRef)getQuery, &dataTypeRef);

if (status==errSecSuccess && dataTypeRef != NULL) {
    NSData *data = (__bridge NSData *)dataTypeRef;

    NSDictionary *newQuery = [NSDictionary dictionaryWithObjectsAndKeys:
        kSecClassKey, kSecClass,
        privateKeyAttrTag, kSecAttrApplicationTag,
        kSecAttrKeyTypeRSA, kSecAttrKeyType,
        kSecAttrAccessibleWhenUnlocked, kSecAttrAccessible, nil];

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

    OSStatus updateItemStatus = SecItemUpdate(
            (__bridge CFDictionaryRef)newQuery, (__bridge CFDictionaryRef)updateAttrs);

    // updateItemStatus == -50, which means "One or more parameters passed to a function were not valid."

}

Solution

  • The problem was because dataTypeRef is not the NSData it self, it is a Dictionary which contains the data.

    The complete code:

    NSString *keyTag = @"mykeytag";
    
    NSDictionary *getQuery = @{
                            (NSString *)kSecClass:              (NSString *)kSecClassKey,
                            (NSString *)kSecAttrApplicationTag: keyTag,
                            (NSString *)kSecAttrKeyType:        (NSString *)kSecAttrKeyTypeRSA,
                            (NSString *)kSecReturnRef:          @YES,
                            (NSString *)kSecAttrAccessible:     (NSString *)kSecAttrAccessibleWhenUnlocked,
                            (NSString *)kSecReturnData:         @YES
                            };
    
    CFDictionaryRef item = NULL;
    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)getQuery, (CFTypeRef *)&item);
    
    if (status == errSecSuccess && item != NULL) {
        NSDictionary *itemDictionary = (__bridge_transfer NSDictionary *)item;
    
        NSMutableDictionary *updateItem = [NSMutableDictionary dictionaryWithDictionary:itemDictionary];
        [updateItem setObject:[getQuery objectForKey:(id)kSecClass] forKey:(id)kSecClass];
    
        NSData *data = itemDictionary[(id)kSecValueData];
    
        NSDictionary *attributesToUpdate = [NSDictionary dictionaryWithObjectsAndKeys:
                                        (NSString *)kSecAttrAccessibleAfterFirstUnlock,
                                        kSecAttrAccessible,
                                        (CFDataRef)data,
                                        kSecValueData,
                                        nil];
    
        OSStatus updateItemStatus = SecItemUpdate((__bridge CFDictionaryRef)updateItem,
                                                (__bridge CFDictionaryRef)attributesToUpdate);
    }