kSecAttrAccount and kSecAttrGeneric
Asked Answered
I

1

1

I would like to save within an account [email protected] two values. Example of the dictionaries:

  • Value 1.

kSecAttrAccount = [email protected]

kSecAttrGeneric = value1Key

kSecValueData = value1

  • Value 2.

kSecAttrAccount = [email protected]

kSecAttrGeneric = value2Key

kSecValueData = value2


Is it possible? I'm getting an error to do the query when I try to keep the second value.

I attach a snippet of my code:

func addCredentials(_ credentials: KeychainCredentials) throws {

let account = credentials.account
let password = credentials.password.data(using: String.Encoding.utf8)!
let generic = credentials.generic

 let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, 
            kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
            .userPresence,
            nil) 

 // Build the query
 let query: [String: Any] = [kSecClass as String: kSecClassGenericPassword,
                                    kSecAttrService as String: serviceName,
                                    kSecAttrAccount as String: account,
                                    kSecAttrGeneric as String: generic,
                                    kSecAttrAccessControl as String: accessControl as Any,
                                    kSecValueData as String: password]

let status = SecItemAdd(query as CFDictionary, nil)
guard status == errSecSuccess else { throw KeychainError(status: status) }

}
Itch answered 13/9, 2019 at 9:32 Comment(0)
T
4

For kSecClassGenericPassword, the combination of service and account must be unique. For the list of which attributes are part of the primary key, see the documentation for errSecDuplicateItem.

The system considers an item to be a duplicate for a given keychain when that keychain already has an item of the same class with the same set of composite primary keys. Each class of keychain item has a different set of primary keys, although a few attributes are used in common across all classes. In particular, where applicable, kSecAttrSynchronizable and kSecAttrAccessGroup are part of the set of primary keys. The additional per-class primary keys are listed below:

For generic passwords, the primary keys include kSecAttrAccount and kSecAttrService.

For internet passwords, the primary keys include kSecAttrAccount, kSecAttrSecurityDomain, kSecAttrServer, kSecAttrProtocol, kSecAttrAuthenticationType, kSecAttrPort, and kSecAttrPath.

For certificates, the primary keys include kSecAttrCertificateType, kSecAttrIssuer, and kSecAttrSerialNumber.

For key items, the primary keys include kSecAttrKeyClass, kSecAttrKeyType, kSecAttrApplicationLabel, kSecAttrApplicationTag, kSecAttrKeySizeInBits, and kSecAttrEffectiveKeySize.

For identity items, which are a certificate and a private key bundled together, the primary keys are the same as for a certificate. Because a private key may be certified more than once, the uniqueness of the certificate determines that of the identity.

If I were building this, I would likely put all the key/values into a dictionary, and serialize that to a single kSecAttrAccount record.

Alternately, you could merge your account and service values together into the account (if you have a service), and put value1Key in the service attribute. Then account+service would be unique to a given key.

Travax answered 13/9, 2019 at 15:38 Comment(1)
Thank you so much, Rob (: I'm gonna develop the first option, a dictionary with all the key/values.Itch

© 2022 - 2024 — McMap. All rights reserved.