Apple keychain 存储客户端身份,因此只有我的应用程序可以访问它
Apple keychain store client identity so only my application could access it
瞄准
我需要以安全的方式将客户端身份存储在 OS X 应用程序上,只有我的应用程序才能访问它。没有提示请求权限。
问题
当我尝试存储客户端身份时,问题立即出现。
这是代码示例(到目前为止我绑定了什么):
- (BOOL)saveClientIdentity:(SecIdentityRef)clientIdentity error:(NSError**) error
{
NSDictionary *attributes = @{
(__bridge id)kSecAttrAccessible:(__bridge id)kSecAttrAccessibleAlwaysThisDeviceOnly,
(__bridge id)kSecValueRef:(__bridge id)clientIdentity,
(__bridge id)kSecAttrApplicationTag:[kMyKeychainAttrApplicationTag dataUsingEncoding: NSUTF8StringEncoding],
(__bridge id)kSecAttrAccessGroup:kMyKeychainAttrAccessGroup
};
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)attributes, NULL);
// status == -25299
…
}
我不断收到代码 -25299 和工具解释问题:
$ security error -25299
Error: 0xFFFF9D2D -25299 The specified item already exists in the keychain.
所以它尝试覆盖全局客户端身份(我从来没有成功地为此应用程序编写过客户端身份,所以不应该有这样的冲突)而且我不知道该怎么做。
它必须只对这个应用程序是私有的。
我验证了各个加载代码会发生什么。它会加载我的开发者身份,但我不希望这样。
- (SecIdentityRef)clientIdentity
{
NSDictionary *attributes =
@{
(__bridge id)kSecClass:(__bridge id)kSecClassIdentity,
(__bridge id)kSecAttrAccessible:(__bridge id)kSecAttrAccessibleAlwaysThisDeviceOnly,
(__bridge id)kSecAttrApplicationTag:[kMyKeychainAttrApplicationTag dataUsingEncoding: NSUTF8StringEncoding],
(__bridge id)kSecAttrAccessGroup:kMyKeychainAttrAccessGroup
};
CFTypeRef universalResult = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)attributes, &universalResult);
SecIdentityRef result = (SecIdentityRef)universalResult;
if (result)
{
CFAutorelease(result);
}
if (status != noErr)
{
NSLog(@"Failed to load client identity: %@", NSErrorFromStatusErrorCode(status));
}
return result;
}
备注
我需要为 iOS 使用相同的代码,但这里应该没有问题,因为默认情况下 iOS 钥匙串不会在应用程序之间共享。
我在 SSKeychain 方面取得了很大的成功,它最近被弃用,取而代之的是 SAMKeychain. 它适用于 iOS 和 Mac 所以它应该解决你的交叉问题也是平台问题。
我找到了很好的解决方案。
诀窍是创建自定义 key-chain 并将客户端身份存储在该密钥链中。
所以基本上有树台阶
首先创建或打开自定义 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));
}
然后将客户端身份添加到 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;
并从钥匙串中读取项目(persistent_ref
可以存储在用户默认值中)
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;
瞄准
我需要以安全的方式将客户端身份存储在 OS X 应用程序上,只有我的应用程序才能访问它。没有提示请求权限。
问题
当我尝试存储客户端身份时,问题立即出现。 这是代码示例(到目前为止我绑定了什么):
- (BOOL)saveClientIdentity:(SecIdentityRef)clientIdentity error:(NSError**) error
{
NSDictionary *attributes = @{
(__bridge id)kSecAttrAccessible:(__bridge id)kSecAttrAccessibleAlwaysThisDeviceOnly,
(__bridge id)kSecValueRef:(__bridge id)clientIdentity,
(__bridge id)kSecAttrApplicationTag:[kMyKeychainAttrApplicationTag dataUsingEncoding: NSUTF8StringEncoding],
(__bridge id)kSecAttrAccessGroup:kMyKeychainAttrAccessGroup
};
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)attributes, NULL);
// status == -25299
…
}
我不断收到代码 -25299 和工具解释问题:
$ security error -25299
Error: 0xFFFF9D2D -25299 The specified item already exists in the keychain.
所以它尝试覆盖全局客户端身份(我从来没有成功地为此应用程序编写过客户端身份,所以不应该有这样的冲突)而且我不知道该怎么做。 它必须只对这个应用程序是私有的。
我验证了各个加载代码会发生什么。它会加载我的开发者身份,但我不希望这样。
- (SecIdentityRef)clientIdentity
{
NSDictionary *attributes =
@{
(__bridge id)kSecClass:(__bridge id)kSecClassIdentity,
(__bridge id)kSecAttrAccessible:(__bridge id)kSecAttrAccessibleAlwaysThisDeviceOnly,
(__bridge id)kSecAttrApplicationTag:[kMyKeychainAttrApplicationTag dataUsingEncoding: NSUTF8StringEncoding],
(__bridge id)kSecAttrAccessGroup:kMyKeychainAttrAccessGroup
};
CFTypeRef universalResult = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)attributes, &universalResult);
SecIdentityRef result = (SecIdentityRef)universalResult;
if (result)
{
CFAutorelease(result);
}
if (status != noErr)
{
NSLog(@"Failed to load client identity: %@", NSErrorFromStatusErrorCode(status));
}
return result;
}
备注
我需要为 iOS 使用相同的代码,但这里应该没有问题,因为默认情况下 iOS 钥匙串不会在应用程序之间共享。
我在 SSKeychain 方面取得了很大的成功,它最近被弃用,取而代之的是 SAMKeychain. 它适用于 iOS 和 Mac 所以它应该解决你的交叉问题也是平台问题。
我找到了很好的解决方案。 诀窍是创建自定义 key-chain 并将客户端身份存储在该密钥链中。
所以基本上有树台阶
首先创建或打开自定义 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)); }
然后将客户端身份添加到 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;
并从钥匙串中读取项目(
persistent_ref
可以存储在用户默认值中)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;