如何不使用已弃用的SecKeychainCopyDomainDefault向System.keychain添加证书
解决MacOS 10.10+下获取系统钥匙串SecKeychainRef的非弃用方法
问题背景
自MacOS 10.10起,SecKeychainCopyDomainDefault已被弃用,但SecItemAdd的kSecUseKeychain键并未弃用,该键需要SecKeychainRef类型的值,目前找不到获取该值的非弃用方法。需求是将CA证书添加到System钥匙串,以下是原本以root身份运行可正常工作但依赖弃用API的代码:
SecKeychainRef system; OSStatus keychainError = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &system); CFDataRef data = CFDataCreate(kCFAllocatorDefault, nsdataCert.bytes, nsdataCert.length); SecCertificateRef test = SecCertificateCreateWithData(kCFAllocatorDefault, data); const void *keys[] = { kSecClass, kSecAttrLabel, kSecValueRef, kSecUseKeychain}; const void *values[] = { kSecClassCertificate , @"Test Certificate", test, system}; CFDictionaryRef query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 4, NULL, NULL); int status = SecItemAdd ((CFDictionaryRef)query, NULL); NSLog(@"status=%d", status);
非弃用解决方案
在MacOS 10.10及以上版本,可以直接通过系统钥匙串的默认路径,使用SecKeychainOpen API获取SecKeychainRef,系统钥匙串的默认路径为/Library/Keychains/System.keychain,修改后的代码如下:
NSString *systemKeychainPath = @"/Library/Keychains/System.keychain"; SecKeychainRef system; OSStatus keychainError = SecKeychainOpen((CFStringRef)systemKeychainPath, &system); if (keychainError == noErr) { CFDataRef data = CFDataCreate(kCFAllocatorDefault, nsdataCert.bytes, nsdataCert.length); SecCertificateRef test = SecCertificateCreateWithData(kCFAllocatorDefault, data); const void *keys[] = { kSecClass, kSecAttrLabel, kSecValueRef, kSecUseKeychain}; const void *values[] = { kSecClassCertificate, @"Test Certificate", test, system}; CFDictionaryRef query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 4, NULL, NULL); int status = SecItemAdd((CFDictionaryRef)query, NULL); NSLog(@"status=%d", status); // 释放CF类型对象,避免内存泄漏 CFRelease(query); CFRelease(test); CFRelease(data); CFRelease(system); } else { NSLog(@"打开系统钥匙串失败: %d", keychainError); }
注意事项
- 操作仍需以root权限运行,系统钥匙串受系统保护,普通用户无写入权限。
- 确认目标系统中
/Library/Keychains/System.keychain路径存在,目前主流MacOS版本均沿用该路径。 - 所有CF类型对象使用完毕后必须调用
CFRelease释放,防止内存泄漏。
内容的提问来源于stack exchange,提问作者Kyle Berezin
相关产品推荐
相关产品推荐

