SecItemCopyMatching - 按名称

时间:2015-09-07 10:12:49

标签: macos keychain

我试图在我的Mac OS X keychain中根据它的名称(kSecAttrLabel)查找特定条目,但看起来SecItemCopyMatching已被破坏,在查找类型为kSecClassIdentity的项目时,不会应用任何过滤。

这段代码将返回所有钥匙串中的所有标识,尽管kSecAttrLabel: @"MyIdentity"参数:

NSDictionary *query = @{ (__bridge id)kSecClass: (__bridge NSString*)kSecClassIdentity,
                     (__bridge id)kSecAttrLabel: @"MyIdentity",
                     (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitAll,
                     (__bridge id)kSecReturnAttributes: @YES,
                     (__bridge id)kSecReturnRef: @YES };

OSStatus status;
status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&privateKey);

当然,我可以通过手动过滤返回的数组来找到我正在寻找的一个身份,但是,除了IMHO之外,它应该正常工作,我还想删除来自我的钥匙串的此身份使用SecItemDelete(),它将查询作为参数,就像SecItemCopyMatching一样。 如果过滤不适用于SecItemCopyMatching,那么它很可能无法为SecItemDelete工作,这意味着如果我尝试拨打,我将简单地删除我的钥匙串的内容SecItemDelete使用此查询。

我做错了什么?

2 个答案:

答案 0 :(得分:0)

我有类似的问题,但我使用的是kSecAttrApplicationTag而不是kSecAttrLabel。无论如何,我不是客观的c也不是IOS安全专家。事实证明我用来创建查找标记的方法不正确。这对我有用:

- (void) getOrCreateKey: (NSNumber*)bits publicIdentifier:(NSString*)publicID

// no!  This appears in several samples, but did not work for me on iOS
// NSData * publicLookupTag = [NSData dataWithBytes:publicId length:strlen((const char *)publicId)];
//
// yes!
NSData * publicLookupTag = [NSData dataWithBytes:[publicId UTF8String] length:publicId.length];

NSMutableDictionary *queryPublicKey = [[NSMutableDictionary alloc] init];

[queryPublicKey setObject:(id)kSecClassKey                forKey:(id)kSecClass];
[queryPublicKey setObject:publicLookupTag                 forKey:(id)kSecAttrApplicationTag];
[queryPublicKey setObject:(id)kSecAttrKeyTypeRSA          forKey:(id)kSecAttrKeyType];
[queryPublicKey setObject:[NSNumber numberWithBool:YES]   forKey:(id)kSecReturnRef];

OSStatus lookupStatus = noErr;
lookupStatus = SecItemCopyMatching((CFDictionaryRef)queryPublicKey, (CFTypeRef *)&publicLookupKey);

答案 1 :(得分:0)

我想我刚刚找到了解决方案。在on another forum上有人建议

  

在身份上使用标签很棘手,因为身份不是作为原子项存储在钥匙串中,而是作为单独的私钥和证书存储,并且这些项以不同的方式使用标签。

这使我意识到一种解决方案是使用SecItemCopyMatching按标签搜索证书,然后使用SecIdentityCreateWithCertificate创建身份。后者的调用应在钥匙串中找到匹配的私钥。这是似乎在macOS Mojave上对我有用的完整代码(在C ++中):

SecIdentityRef identity = nullptr;
const char* certificateName = ...;
const void* keys[] = {
    kSecClass,
    kSecMatchLimit,
    kSecReturnRef,
    kSecAttrLabel
};
const void* values[] = {
    kSecClassCertificate,
    kSecMatchLimitOne,
    kCFBooleanTrue,
    CFStringCreateWithCString(nullptr, certificateName, kCFStringEncodingUTF8)
};
CFDictionaryRef query = CFDictionaryCreate(nullptr, keys, values, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFTypeRef result;
OSStatus status = SecItemCopyMatching(query, &result);
CFRelease(query);
CFRelease(values[3]);
if (status) {
    // error
}
else {
    SecCertificateRef certificate = (SecCertificateRef)result;
    status = SecIdentityCreateWithCertificate(nullptr, certificate, &identity);
    CFRelease(certificate);
    if (status) {
        // error
    }
}