SecItemAdd Error Adding key to keychain

OS X 10.3.3, Xcode 7 beta 2. This simple function to add a key to a keychain in Swift is failing and I don't know why. Searching for the error hasn't been much help. The error is:


Swift.Unmanaged<ObjectiveC.CFString>(_value: The specified attribute does not exist.)

The number of attributes have been cut to what I think is the minimum. The code copied straight from a playground:


func addKeyToKeychain() -> NSData? {
    let keyId = "org.snafu.testKey".dataUsingEncoding(NSUTF8StringEncoding,
                                                          allowLossyConversion: false)!
    let keyData = NSMutableData(length: 64)!
    let result = SecRandomCopyBytes(kSecRandomDefault, 64,
                                    UnsafeMutablePointer<UInt8>(keyData.mutableBytes))
    assert(result == 0)

    let attributes: [NSString: AnyObject] = [
        kSecClass: kSecClassKey,
        kSecAttrApplicationTag: keyId,
        kSecValueData: keyData,
        kSecAttrKeySizeInBits: 512
    ]
    let status = SecItemAdd(attributes as CFDictionary, nil)
    if status != errSecSuccess {
        print(SecCopyErrorMessageString(status, nil))
        return nil
    }
    return keyData
}


Any ideas? Is this the proper place to be asking this question?

Well, that was an interesting experience. Apperently SecItemAdd doesn't like the dictionary I created. I played with several iteration before I found one that worked. Coding it this way did the trick:


   let attributes: [String: AnyObject] = [
        String(kSecClass): kSecClassKey,
        String(kSecAttrApplicationTag): keyId,
        String(kSecValueData): keyData,
        String(kSecAttrKeySizeInBits): "512"
    ]


I don't think the change from NSString to String and the explicit conversions did anything. However when I changed 512 to "512" the error went away and the key was added to my keychain.

I guess I'm talking to myself. Anway... the above only seems to work. It creates an entry in the loging keychain but the entry can't be found. Dumping the keychain with security(1) shows the item to be mostly null. I suppose that is not surprising as kSecAttrKeySizeInBits should be a CFNumberRef, not a string. However, when I use a NSNumber which should be toll free bridged I'm back to the "The specified attribute does not exist." error.


Even worse: the added item can not be deleted using the keychain access app. When I try to delete the item Keychain Access says


An error occurred while deleting “org.snafu.testKey.”

A missing value was detected.

I suspect that you have both Swift and Security framework issues here. I'm going to focus on the Security framework side of things first, because that's the most significant.

What type of key are you trying to generate? You're creating a key from random bytes, which implies that you're trying to deal with a symmetric key. If so, I recommend

SecKeyGenerateSymmetric
, which is likely to easier to use that the lower-level
SecItemAdd
(the problem with the latter being that you have to get all of the key's myriad attributes right before things will work correctly).

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
SecItemAdd Error Adding key to keychain
 
 
Q