Apple钥匙串存储了客户端身份,因此只有我的应用程序可以访问它 [英] Apple keychain store client identity so only my application could access it

查看:162
本文介绍了Apple钥匙串存储了客户端身份,因此只有我的应用程序可以访问它的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要以安全的方式将客户端身份存储在OS X应用程序中,以便只有我的应用程序才能访问它.没有提示询问权限.

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.

当我尝试存储客户端身份时,问题立即出现. 这是代码示例(到目前为止我有什么联系):

Problem appeared immediately when I was trying to store client identity. Here is code sample (what have I tied so far):

- (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,工具提示问题所在:

I'm constantly getting code -25299 and tool expalint the problem:

$ security error -25299
Error: 0xFFFF9D2D -25299 The specified item already exists in the keychain.

因此,它尝试覆盖全局客户端身份(我从未成功为该应用程序编写客户端身份,因此不应发生此类冲突),我也没有做什么. 对于此应用程序,它必须是私有的.

So it tries override global client identity (I never successful written a client identity for this application so there shouldn't be such conflict) and I don't what to do that. It have to be private for only this application.

我验证了相应加载代码会发生什么.它加载了我的开发人员身份,但我不希望那样.

I verified what happens for respective loading code. It loads my developer identity and I do not want that.

- (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钥匙串.

Notes

I need to use same code for iOS, but here should be no problem since by default iOS keychain is not shared between applications.

推荐答案

我找到了不错的解决方案. 诀窍是创建自定义密钥链,然后在该密钥链中存储客户端身份.

I've found nice solution. The trick is to create custom key-chain and than store client identity in that key chain.

所以基本上有树步骤.

  1. 首先创建或打开自定义钥匙串:

  1. 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;
    

  • 并从钥匙串中读取项目(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;
    

  • 这篇关于Apple钥匙串存储了客户端身份,因此只有我的应用程序可以访问它的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆