我有一个客户端从服务器检索证书 (.pfx),包括私钥,我使用以下代码将其添加到本地钥匙串(keychain):-
void AddCertToKeyChain(const QByteArray& cert, const QString& password)
{
SecKeychainRef keyChain = nil;
OSStatus err = SecKeychainCopyDomainDefault(kSecPreferencesDomainUser, &keyChain);
if (err != errSecSuccess)
{
emit Log("Failed to access system keychain: " + LogMessageForStatus(err));
return;
}
SecExternalFormat format = kSecFormatPKCS12;
SecExternalItemType itemType = kSecItemTypeAggregate;
SecItemImportExportFlags flags = 0;
SecItemImportExportKeyParameters params;
memset(¶ms, 0, sizeof(params));
params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
params.flags = 0;
params.passphrase = password.toCFString();
params.alertTitle = NULL;
params.alertPrompt = NULL;
params.accessRef = NULL;
// create and populate the key usage array
CFMutableArrayRef keyUsage = CFArrayCreateMutable(
kCFAllocatorDefault,
0,
&kCFTypeArrayCallBacks
);
CFArrayAppendValue(keyUsage, kSecAttrCanEncrypt);
CFArrayAppendValue(keyUsage, kSecAttrCanDecrypt);
CFArrayAppendValue(keyUsage, kSecAttrCanDerive);
CFArrayAppendValue(keyUsage, kSecAttrCanSign);
CFArrayAppendValue(keyUsage, kSecAttrCanVerify);
CFArrayAppendValue(keyUsage, kSecAttrCanWrap);
CFArrayAppendValue(keyUsage, kSecAttrCanUnwrap);
keyUsage = NULL; // Error without this - Failed to import certificate: The key usage mask is not supported.
// create and populate the key attributes array
CFMutableArrayRef keyAttributes = CFArrayCreateMutable(
kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks
);
// required for import
params.keyUsage = keyUsage;
params.keyAttributes = keyAttributes;
OSStatus status = SecItemImport(cert.toCFData(), CFSTR(".p12"), &format, &itemType, flags, ¶ms, keyChain, NULL);
if(status == errSecSuccess)
emit Log("Certificate successfully imported");
else
{
emit Log("Failed to import certificate: " + LogMessageForStatus(status));
}
}
如预期的那样,证书和私钥出现在钥匙串(keychain)中。
但是,无论是通过编程还是使用 Keychain 应用程序,尝试检索证书都是一个问题。
如果我选择从钥匙串(keychain)导出私钥,我会在对话框中看到以下错误:-
"An error has occurred. Unable to export an item. The contents of this item cannot be retrieved"
但是,如果通过双击 pfx 将证书和 key 添加到钥匙串(keychain),则可以按预期导出 key 。
那么,为什么上面的代码会导致无法导出 key 的问题呢?
最佳答案
在 Apple 的 Quinn 的帮助下,问题中描述的方法似乎应该有效,但没有。
使用旧的 CDSA 风格标志实际上是可行的,做这样的事情:-
OSStatus err;
SecExternalFormat format;
SecItemImportExportKeyParameters params;
params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
params.flags = 0;
params.passphrase = (__bridge CFStringRef) pkcs12Password;
params.alertTitle = NULL;
params.alertPrompt = NULL;
params.accessRef = NULL;
params.keyUsage = NULL;
params.keyAttributes = (__bridge CFArrayRef) @[ @(CSSM_KEYATTR_EXTRACTABLE) ];
format = kSecFormatPKCS12;
err = SecItemImport(
(__bridge CFDataRef) pkcs12Data,
CFSTR("p12"),
&format,
NULL,
0,
¶ms,
keychain,
NULL
);
注意 params.keyAttributes 的设置,它定义了可提取的 key 。
或者,可以使用旧的(已弃用的)SecKeychainItemImport API:-
BOOL success;
OSStatus err;
NSArray * result;
SecExternalFormat format;
SecKeyImportExportParameters params;
CFArrayRef importedItems;
result = nil;
importedItems = NULL;
format = kSecFormatPKCS12;
memset(¶ms, 0, sizeof(params));
params.passphrase = password;
params.keyAttributes = CSSM_KEYATTR_EXTRACTABLE;
err = SecKeychainItemImport(
(CFDataRef) pkcs12Blob, // importedData
NULL, // fileNameOrExtension
&format, // inputFormat
NULL, // itemType
0, // flags
¶ms, // keyParams
self->keychain, // importKeychain
&importedItems // outItems
);
success = (err == noErr);
虽然函数 SecKeychainItemImport 在 Apple 的文档中被定义为已弃用,但我被告知它不太可能很快被删除。
关于c - 将证书插入钥匙串(keychain),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26781597/