I need to store client identity on OS X application in secure way in such way that only my application could access it. No prompting asking for permissions.
I've had a lot of success with SSKeychain, which was recently deprecated in favor of SAMKeychain. It works for both iOS and Mac so it should address your cross-platform issue too.
I've found nice solution. The trick is to create custom key-chain and than store client identity in that key chain.
So basically there are tree steps.
First create or open custom key-chain:
NSString *keychainpath = self.customKeychainPath;
unsigned char password[SHA_DIGEST_LENGTH];
GenerateCustomKeychainPassword(password);
OSStatus status = SecKeychainCreate(keychainpath.UTF8String,
SHA_DIGEST_LENGTH,
password,
NO,
NULL,
&customKeychain);
if (status == errSecDuplicateKeychain)
{
status = SecKeychainOpen(keychainpath.UTF8String, &customKeychain);
if (status == errSecSuccess)
{
status = SecKeychainUnlock(customKeychain,
SHA_DIGEST_LENGTH,
password,
TRUE);
if (status != errSecSuccess)
{
NSLog(@"%s Failed to unlock custom keychain: %@",
__PRETTY_FUNCTION__, NSErrorFromStatusErrorCode(status));
}
}
}
else if (status != errSecSuccess)
{
NSLog(@"%s Failed to unlock custom keychain: %@",
__PRETTY_FUNCTION__, NSErrorFromStatusErrorCode(status));
}
Than add client identity to that key-chain
OSStatus status = errSecSuccess;
CFTypeRef persistent_ref = NULL;
NSDictionary *dict = @{
(id)kSecValueRef:(id)secItem,
(id)kSecReturnPersistentRef:(id)kCFBooleanTrue,
#if !TARGET_OS_IPHONE
(id)kSecUseKeychain:(__bridge id)customKeychain,
#endif
};
status = SecItemAdd((CFDictionaryRef)dict, &persistent_ref);
NSCAssert(status != errSecParam, @"Wrong contents of dictionary");
if (status == errSecDuplicateItem)
{
NSLog(@"%s Item: %@ already exists", __PRETTY_FUNCTION__, secItem);
return NULL;
}
return (CFDataRef)persistent_ref;
And to read item from a keychain (persistent_ref
can be stored in user defaults)
NSDictionary *dict = @{
(id)kSecClass:(__bridge id)itemType,//kSecClassIdentity,
(id)kSecReturnRef:(id)kCFBooleanTrue,
(id)kSecValuePersistentRef:persistantRef,
#if !TARGET_OS_IPHONE
(id)kSecUseKeychain:(__bridge id)customKeychain,
#endif
};
OSStatus status = SecItemCopyMatching((CFDictionaryRef)dict, &result);
NSCAssert(status != errSecParam, @"Invalid arguments");
return result;