获取钥匙串证书

时间:2011-04-24 00:53:31

标签: cocoa security macos keychain appkit

我查看了安全框架文档,但我似乎无法找到获取给定钥匙串上所有证书的方法。有没有办法来实现这个目标?

2 个答案:

答案 0 :(得分:15)

如果您定位到Mac OS 10.6或更高版本,则可以使用SecItemCopyMatching轻松查询钥匙串:

SecKeychainRef keychain = ...
NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys:
                       kSecClassCertificate, kSecClass, 
                       [NSArray arrayWithObject:(id)keychain], kSecMatchSearchList,
                       kCFBooleanTrue, kSecReturnRef,
                       kSecMatchLimitAll, kSecMatchLimit,
                       nil];
NSArray *items = nil;
OSStatus status = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef *)&items);
if (status) {
    if (status != errSecItemNotFound)
        LKKCReportError(status, @"Can't search keychain");
    return nil;
}
return [items autorelease]; // items contains all SecCertificateRefs in keychain

请注意,您不得使用它来实现证书验证 - 钥匙串中存在CA证书并不表示可信任签署任何特定策略的证书。请参阅证书,密钥和信任编程指南,了解如何使用Keychain进行证书验证。

http://developer.apple.com/library/mac/#documentation/Security/Conceptual/CertKeyTrustProgGuide/03tasks/tasks.html#//apple_ref/doc/uid/TP40001358-CH205-SW1

答案 1 :(得分:14)

在挖掘文档,头文件和源文件之后,我想出了以下代码:

#import <Security/Security.h>

- (void)logMessageForStatus:(OSStatus)status
               functionName:(NSString *)functionName
{
    CFStringRef errorMessage;
    errorMessage = SecCopyErrorMessageString(status, NULL);
    NSLog(@"error after %@: %@", functionName, (NSString *)errorMessage);
    CFRelease(errorMessage);  
}

- (void)listCertificates
{
    OSStatus status;
    SecKeychainSearchRef search = NULL;

    // The first argument being NULL indicates the user's current keychain list
    status = SecKeychainSearchCreateFromAttributes(NULL,
        kSecCertificateItemClass, NULL, &search);

    if (status != errSecSuccess) {
        [self logMessageForStatus:status
                     functionName:@"SecKeychainSearchCreateFromAttributes()"];
        return;
    }

    SecKeychainItemRef searchItem = NULL;

    while (SecKeychainSearchCopyNext(search, &searchItem) != errSecItemNotFound) {
        SecKeychainAttributeList attrList;
        CSSM_DATA certData;

        attrList.count = 0;
        attrList.attr = NULL;

        status = SecKeychainItemCopyContent(searchItem, NULL, &attrList,
            (UInt32 *)(&certData.Length),
            (void **)(&certData.Data));

        if (status != errSecSuccess) {
            [self logMessageForStatus:status
                         functionName:@"SecKeychainItemCopyContent()"];
            CFRelease(searchItem);
            continue;
        }

        // At this point you should have a valid CSSM_DATA structure
        // representing the certificate

        SecCertificateRef certificate;
        status = SecCertificateCreateFromData(&certData, CSSM_CERT_X_509v3,
            CSSM_CERT_ENCODING_BER, &certificate);

        if (status != errSecSuccess) {
            [self logMessageForStatus:status
                         functionName:@"SecCertificateCreateFromData()"];
            SecKeychainItemFreeContent(&attrList, certData.Data);
            CFRelease(searchItem);
            continue;
        }

        // Do whatever you want to do with the certificate
        // For instance, print its common name (if there's one)

        CFStringRef commonName = NULL;
        SecCertificateCopyCommonName(certificate, &commonName);
        NSLog(@"common name = %@", (NSString *)commonName);
        if (commonName) CFRelease(commonName);

        SecKeychainItemFreeContent(&attrList, certData.Data);
        CFRelease(searchItem);
    }

    CFRelease(search);
}