SecItemCopyMatching无法读取iCloud钥匙串

时间:2014-05-07 23:58:31

标签: macos cocoa icloud keychain

我从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 :(得分: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 Developer forum threadSecItemCopyMatching 及以后。

Apple 在记录 SecItem* API 系列方面做得很差。信息在那里,但散布在不同(不相关)的地方(有些甚至在官方文档之外)。

1:通过(id)kSecReturnData: (id)kCFBooleanTrue获取key的数据;但是你can't use kSecReturnData and kSecMatchLimitAll together