Aim
我需要以安全的方式在 OS X 应用程序上存储客户端身份,以便只有我的应用程序可以访问它。没有提示请求权限。
Problem
当我尝试存储客户身份时,问题立即出现。
这是代码示例(到目前为止我已经绑定了什么):
- (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;
}
Notes
我需要对 iOS 使用相同的代码,但是这里应该没有问题,因为默认情况下 iOS 钥匙串不在应用程序之间共享。