I’m developing an iOS application and aiming to install a PKCS#12 (.p12) certificate into the com.apple.token keychain access group so that Microsoft Edge for iOS, managed via MDM/Intune, can read and use it for client certificate authentication.
I’m attempting to save to the com.apple.token keychain access group, but I’m getting error -34018 (errSecMissingEntitlement) and the item isn’t saved. This occurs on both a physical device and the simulator.
I’m using SecItemAdd from the Security framework to store it. Is this the correct approach? https://developer.apple.com/documentation/security/secitemadd(::)
I have added com.apple.token to Keychain Sharing.
I have also added com.apple.token to the app’s entitlements.
Here is the code I’m using to observe this behavior:
public static func installToTokenGroup(p12Data: Data, password: String) throws -> SecIdentity {
// First, import the P12 to get the identity
let options: [String: Any] = [
kSecImportExportPassphrase as String: password
]
var items: CFArray?
let importStatus = SecPKCS12Import(p12Data as CFData, options as CFDictionary, &items)
guard importStatus == errSecSuccess,
let array = items as? [[String: Any]],
let dict = array.first
else {
throw NSError(domain: NSOSStatusErrorDomain,
code: Int(importStatus),
userInfo: [NSLocalizedDescriptionKey: "Failed to import P12: \(importStatus)"])
}
let identity = dict[kSecImportItemIdentity as String] as! SecIdentity
let addQuery: [String: Any] = [
kSecClass as String: kSecClassIdentity,
kSecValueRef as String: identity,
kSecAttrLabel as String: kSecAttrAccessGroupToken,
kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlock,
kSecAttrAccessGroup as String: kSecAttrAccessGroupToken
]
let status = SecItemAdd(addQuery as CFDictionary, nil)
if status != errSecSuccess && status != errSecDuplicateItem {
throw NSError(domain: NSOSStatusErrorDomain,
code: Int(status),
userInfo: [NSLocalizedDescriptionKey: "Failed to add to token group: \(status)"])
}
return identity
}
Thanks for bringing this to the forums.
The com.apple.token keychain access group, aka kSecAttrAccessGroupToken, isn’t a normal keychain access group. Rather, it’s a special group that holds all of the credentials that the system finds in CryptoTokenKit (CTK) tokens. Given that, you can’t add credentials to this group directly.
It is possible to create a persistent CTK token, that is, one that’s not tied to smart card hardware. If you do that then the credentials published by that token will be available to all apps that are set up to use token-based credentials.
It’s not clear whether this approach will work for your ultimate goal:
so that Microsoft Edge for iOS … can … use it for client certificate authentication
My advice is that you first prototype this with an actual smart card [1]. If you can get that working, it’d be worth exploring the virtual token option.
Finally, if you’re curious how an app can work with token-based credentials, see this post.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
[1] I have a YubiKey that I use for tests like this.