SecItemCopyMatching无法读取iCloud钥匙串

6

我从Stack Overflow上获取了一些访问Web浏览器密码的代码。只要密码在登录钥匙串中,它就可以很好地工作。但是,我感兴趣的特定帐户在某个时候被移动到iCloud钥匙串中,并且不再存在于登录钥匙串中。SecItemCopyMatching找不到它。它返回OSStatus -23500,即“未找到项目”。我如何访问这些条目?

CFArrayRef result = NULL;
NSDictionary *params = @{ (__bridge id)kSecClass            : (__bridge id)kSecClassInternetPassword,
                        (__bridge id)kSecMatchLimit       : (__bridge id)kSecMatchLimitAll,
                        (__bridge id)kSecReturnAttributes : (__bridge id)kCFBooleanTrue,
                        (__bridge id)kSecAttrProtocol     : (__bridge id)kSecAttrProtocolHTTPS,
                        (__bridge id)kSecAttrServer       : @"accounts.mydomain.com"
                        };
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)(params), (CFTypeRef *) &result);

if (status == noErr) {
   // item found!
}
1个回答

0

虽然在macOS上您可以看到登录和iCloud钥匙串,但前者是macOS风格的钥匙串,而后者是iOS风格的钥匙串。只要用户同意,应用程序就可以自由访问macOS风格的钥匙串项目。iOS风格的项目严格遵循访问组策略。

iCloud钥匙串中的每个密钥都在一个访问组下。调用SecItemCopyMatching的应用程序应该将所说的访问组作为密钥的授权才能出现在查询结果中。

一旦确定搜索的密钥的访问组位于您的应用程序授权列表中列出的访问组之一,您必须传递一些属性到SecItemCopyMatching查询字典中(除了强制性的属性如kSecClass):

  1. kSecAttrAccessGroup
  2. kSecAttrSynchronizable

如果您的应用程序有多个访问组权限,请通过kSecAttrAccessGroup设置正确的组。将kSecAttrSynchronizable设置为kCFBooleanTrue,仅搜索iOS样式的项目(这些项目已同步);将其设置为kSecAttrSynchronizableAny会搜索已同步和未同步的密钥(例如登录钥匙串中的密钥)。默认情况下,仅搜索本地密钥(kCFBooleanFalse)。

示例查询

这将返回一个字典数组;每个密钥对应一个字典;所有iCloud密钥都可以被您的应用程序访问。每个字典中的键值对都是相应密钥的属性;这不会返回密钥的值1

    NSString* account = @"my_account";
    NSString* service = @"some_service";

    NSDictionary* query = @{
        (id)kSecClass: (id) kSecClassGenericPassword,
        // skip as this example app has only one access group
        // (id)kSecAttrAccessGroup: (id) keychainAccessGroup,
        (id)kSecAttrSynchronizable: (id)kCFBooleanTrue,
        (id)kSecAttrAccount: (id) account,
        (id)kSecAttrService: (id) service,
        (id)kSecReturnAttributes: (id)kCFBooleanTrue,
        (id)kSecMatchLimit: (id)kSecMatchLimitAll,
    };

    CFTypeRef result;
    OSStatus status = SecItemCopyMatching((CFDictionaryRef)query, &result);
    if (status != errSecSuccess) {
        CFStringRef err = SecCopyErrorMessageString(status, nil);
        NSLog(@"Error: %@", err);
        CFRelease(err);
    } else {
        NSArray* attributes_of_keys = (__bridge NSArray*)result;
    }

在调试器下检查attributes_of_keys应该会告诉你很多信息。

来源: Apple开发者论坛帖子, SecItemCopyMatching及其后续操作。

苹果在文档化SecItem* API家族方面做得很糟糕。虽然有信息,但是分散在不同的(无关的)地方(甚至在官方文档之外)。

1:传递(id)kSecReturnData: (id)kCFBooleanTrue以获取密钥的数据;但是不能同时使用kSecReturnDatakSecMatchLimitAll


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接