I have been trying to find a way to be able to sign some data with private key of an identity in login keychain without raising any prompts.
I am able to do this with system keychain (obviously with correct permissions and checks) but not with login keychain. It always ends up asking user for their login password.
Here is how the code looks, roughly,
NSDictionary *query = @{
(__bridge id)kSecClass: (__bridge id)kSecClassIdentity,
(__bridge id)kSecReturnRef: @YES,
(__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitAll
};
CFTypeRef result = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&result);
NSArray *identities = ( NSArray *)result;
SecIdentityRef identity = NULL;
for (id _ident in identities) {
// pick one as required
}
SecKeyRef privateKey = NULL;
OSStatus status = SecIdentityCopyPrivateKey(identity, &privateKey);
NSData *strData = [string dataUsingEncoding:NSUTF8StringEncoding];
unsigned char hash[CC_SHA256_DIGEST_LENGTH];
CC_SHA256(strData.bytes, (CC_LONG)strData.length, hash);
NSData *digestData = [NSData dataWithBytes:hash length:CC_SHA256_DIGEST_LENGTH];
CFErrorRef cfError = NULL;
NSData *signature = (__bridge_transfer NSData *)SecKeyCreateSignature(privateKey,
kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256,
(__bridge CFDataRef)digestData,
&cfError);
Above code raises these system logs in console
default 08:44:52.781024+0000 securityd client is valid, proceeding
default 08:44:52.781172+0000 securityd code requirement check failed (-67050), client is not Apple-signed
default 08:44:52.781233+0000 securityd displaying keychain prompt for /Applications/Demo.app(81692)
If the key is in login keychain, is there any way to do SecKeyCreateSignature without raising prompts? What does client is not Apple-signed mean?
PS: Identities are pre-installed either manually or via some device management solution, the application is not installing them.
Before you start, read TN3137 On Mac keychain APIs and implementations because the following uses terms from that.
Identities are pre-installed … the application is not installing them.
Right. This is where things go wrong. By default an app from Team A can’t access credentials created by an app from Team B, or by the system.
With the data protection keychain this is easier to understand because your app can’t even see items outside of its keychain access groups. However, this security policy was retrofitted to the file-based keychain, which makes things more confusing. It can see the item but triggers an access control alert when it uses it.
On iOS, where there is only the data protection keychain, this has been a source of much annoyance over the years. Fortunately, there’s a shiny new API to help with that, namely ManagedApp. Unfortunately this isn’t on macOS, so it doesn’t help you.
As to what you can do, the answer is gonna depend on how these keys are provisioned and what your app does with them. For example, if the user is involved then can use Keychain Access (or the security tool) to change the key’s ACL. If you can explain more about your specific requirements, I might be able to suggest more options.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"