SecItemAdd with kSecAttrAccessControl Error

Hi

I'm trying to add to the Keychain with access control flags. However the OSStatus returns -50 One or more parameters passed to a function were not valid.

Here is the function I've written causing the error:

public func addItem(value: Data, forKey: String, accessControlFlags: SecAccessControlCreateFlags? = nil) {
   guard !forKey.isEmpty else {
      return
   }

   var query: [String: Any] = [kSecClass as String: kSecClassGenericPassword,
   kSecAttrService as String: Bundle.main.bundleIdentifier!,
   kSecAttrAccount as String: forKey,
   kSecValueData as String: value,
   kSecAttrSynchronizable as String: false
   kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlock]

   // Check if any access control is to be applied.
   if let accessControlFlags = accessControlFlags {
      var error: Unmanaged<CFError>?

      guard let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, accessControlFlags, &error) else {
         return
      }

      query[kSecAttrAccessControl as String] = accessControl
   }

   let status = SecItemAdd(query as CFDictionary, nil)
   
   guard status != errSecDuplicateItem else {
      return
   }

   guard status == errSecSuccess else {
      let message = SecCopyErrorMessageString(status, nil) as String? ?? "Unknown error"
      print(message)
      return
   }
}

Any ideas why this might be occurring, if kSecAttrAccessControl is not added to the query parameter, then it works fine.

Thanks

Replies

You’ve set kSecAttrSynchronizable to false so you’re targeting the macOS file-based keychain, which doesn’t support kSecAttrAccessControl. If you want to create an item in the data protection (iOS-style) keychain without it being synchronised, set kSecUseDataProtectionKeychain.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Hi Quinn

Thanks for the reply. I removed kSecAttrSynchronizable added kSecUseDataProtectionKeychain. For now, I also removed kSecAttrAccessible as part of the initial query. Here is the refactored code:

public func addItem(value: Data, forKey: String, accessControlFlags: SecAccessControlCreateFlags? = nil) {
   guard !forKey.isEmpty else {
      return
   }

   var query: [String: Any] = [kSecClass as String: kSecClassGenericPassword,
   kSecAttrService as String: Bundle.main.bundleIdentifier!,
   kSecAttrAccount as String: forKey,
   kSecValueData as String: value,
   kSecUseDataProtectionKeychain as String: true]

   // Check if any access control is to be applied.
   if let accessControlFlags = accessControlFlags {
      var error: Unmanaged<CFError>?

      guard let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, accessControlFlags, &error) else {
         return
      }

      query[kSecAttrAccessControl as String] = accessControl
   }

   let status = SecItemAdd(query as CFDictionary, nil)
   
   guard status != errSecDuplicateItem else {
      return
   }

   guard status == errSecSuccess else {
      let message = SecCopyErrorMessageString(status, nil) as String? ?? "Unknown error"
      print(message)
      return
   }
}

And to invoke the function:

try? addItem(value: "Hello World", forKey: "greeting", accessControlFlags: [.userPresence])

The error which occurs in both the simulator and device is -25293 The user name or passphrase you entered is not correct.

Appreciate if you have any guidance on this one...

Thanks

Hmmm, this is on the Mac, right?

Earlier I just assumed that, but I need to confirm that before I dig into this further.

And, assuming I was correct, I’m further assuming:

Correct?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Hey Quinn Nuh, this is for iOS devices. This code use to work on iOS14, but busted on iOS15 🤷‍♂️ I found probably feedback reference to the same issue (FB9414546), so maybe a bug...

Cheers

Any update for this question? I got the same error when using kSecAttrAccessControl. on mac

only works when using kSecAttrAccessible

Keychains on the Mac are confusing. Before going further, read my On Mac Keychains post.

In your case, kSecAttrAccessControl is only applicable to the data protection keychain, so you have to specific either kSecUseDataProtectionKeychain or kSecAttrSynchronizable. If you’re doing that and still see a problem, please post a snippet of how you set up the dictionary you pass to SecItemAdd.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"