Adding private key into iOS Keychain

23,959

Solution 1

The following code worked for me:

NSMutableDictionary *query = [[NSMutableDictionary alloc] init]; 
[query setObject:(id)kSecClassKey forKey:(id)kSecClass]; 
[query setObject:(id)kSecAttrAccessibleWhenUnlocked forKey:(id)kSecAttrAccessible]; 
[query setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnData];

//adding access key 
[query setObject:(id)key forKey:(id)kSecAttrApplicationTag];


//removing item if it exists 
SecItemDelete((CFDictionaryRef)query);

//setting data (private key) 
[query setObject:(id)data forKey:(id)kSecValueData];

CFTypeRef persistKey; OSStatus status = SecItemAdd((CFDictionaryRef)query, &persistKey);

if(status) {
    NSLog(@"Keychain error occured: %ld (statuscode)", status);
    return NO; 
}

Solution 2

Sorry but I'll never be able to debug your code. Apple provides some sample code (KeychainItemWrapper) which lets you save one string (I recall). Its a big help dealing with the key chain. There is a gist on the web that is a modified version of that class, but saves and restores a dictionary (archived as a data object, which is what the Apple code does to the string). This lets you save multiple items in one interface to the keychain. The gist is here Keychain for NSDictionary/data

Share:
23,959
Chris
Author by

Chris

Updated on January 30, 2020

Comments

  • Chris
    Chris over 4 years

    I am trying to add a private key into the iOS keychain. The certificate (public key) works fine but the private key refuses... I am totally confused why the following code does not work.

    First I am checking if the current key (=key in case of that the Keychain is a key/value store) is 'free' in the Keychain. Then I am going to add the private key.

    CFStringRef labelstring = CFStringCreateWithCString(NULL, [key cStringUsingEncoding:NSUTF8StringEncoding], kCFStringEncodingUTF8);
    
    NSArray* keys = [NSArray arrayWithObjects:(__bridge id)kSecClass,kSecAttrLabel,kSecReturnData,kSecAttrAccessible,nil];
    NSArray* values = [NSArray arrayWithObjects:(__bridge id)kSecClassKey,labelstring,kCFBooleanTrue,kSecAttrAccessibleWhenUnlocked,nil];
    NSMutableDictionary* searchdict = [NSMutableDictionary dictionaryWithObjects:values forKeys:keys];
    
    CFRelease(labelstring);
    
    NSMutableDictionary *query = searchdict;
    
    
    CFTypeRef item = NULL;
    OSStatus error = SecItemCopyMatching((__bridge_retained CFDictionaryRef) query, &item);
    
    if (error)
    {
        NSLog(@"Error: %ld (statuscode)", error);
    }
    
    if(error != errSecItemNotFound)
    {
        SecItemDelete((__bridge_retained CFDictionaryRef) query);
    }
    
    [query setObject:(id)data forKey:(__bridge id)kSecValueData];
    
    OSStatus status = SecItemAdd((__bridge_retained CFDictionaryRef) query, &item);
    
    if(status)
    {
        NSLog(@"Keychain error occured: %ld (statuscode)", status);
        return NO;
    }
    

    The debug output is the following:

    2012-07-26 15:33:03.772 App[15529:1b03] Error: -25300 (statuscode)
    2012-07-26 15:33:11.195 App[15529:1b03] Keychain error occured: -25299 (statuscode)
    

    The first error code -25300 represents errSecItemNotFound. So there is no value stored for this key. Then, when I try to add the private key into the Keychain I get -25299 which means errSecDuplicateItem. I do not understand this. Why is this happening?

    Does anyone have a clue or hint on this?

    Apple's error codes:

    errSecSuccess                = 0,       /* No error. */
    errSecUnimplemented          = -4,      /* Function or operation not implemented. */
    errSecParam                  = -50,     /* One or more parameters passed to a function where not valid. */
    errSecAllocate               = -108,    /* Failed to allocate memory. */
    errSecNotAvailable           = -25291,  /* No keychain is available. You may need to restart your computer. */
    errSecDuplicateItem          = -25299,  /* The specified item already exists in the keychain. */
    errSecItemNotFound           = -25300,  /* The specified item could not be found in the keychain. */
    errSecInteractionNotAllowed  = -25308,  /* User interaction is not allowed. */
    errSecDecode                 = -26275,  /* Unable to decode the provided data. */
    errSecAuthFailed             = -25293,  /* The user name or passphrase you entered is not correct. */ 
    

    Thanks in advance!

    Update #1: I've figured out that it works only for the first time. Even when data and key is different, after the first time stored into the keychain I cannot store further keys.