Search code examples
swiftkeychain

Keychain SecItemUpdate returning errSecParam


I can add items to the keychain, I can even read them out.

However, I'm struggling to use SecItemUpdate to update a value, and seem to get errSecParam returned every time.

To do so I'm creating the following query and attributes (very likely to be an issue here)

let query: [String: Any] = [kSecAttrAccount as String : "MyString",
    kSecValueData as String: "test2".data(using: .utf16)!,
    kSecMatchLimit as String  : kSecMatchLimitOne
]

let attributes: [String: Any] = [kSecAttrAccount as String: "aa",
                                         kSecValueData as String: data]

which is then used to update

SecItemUpdate(query as CFDictionary, attributes as CFDictionary)


Solution

  • It should be specified class in query and not data (for update), so, for example, to add/update password in keychain it should be as following

    // adding item
    let addQuery: [CFString: Any] = [
        kSecClass: kSecClassGenericPassword,
        kSecAttrService: service as CFString,        // eg. "www.mysite.com"
        kSecAttrAccount: name as CFString            // eg. "user"
        kSecValueData: password.data(using: .utf8)   // eg. "password"
    ] as CFDictionary
    
    if errSecSuccess != SecItemAdd(addQuery, nil) { 
        // report error here
    }
    
    // updating item (same query is for SecItemDelete)
    
    let updateQuery: [CFString: Any] = [
        kSecClass: kSecClassGenericPassword,
        kSecAttrService: service as CFString,        // eg. "www.mysite.com"
        kSecAttrAccount: name as CFString            // eg. "user"
    ] as CFDictionary
    
    let newAttributes = [
        kSecAttrAccount: newName as CFString            // eg. "user1"
        kSecValueData: newPassword.data(using: .utf8)   // eg. "password1"
    ] as CFDictionary
    
    if errSecSuccess != SecItemUpdate(updateQuery, newAttributes) {
       // report error here
    }