将证书插入钥匙串

3

我有一个客户端从服务器检索证书(.pfx),包括私钥,并用以下代码将其添加到本地钥匙链中:

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(&params, 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, &params, keyChain, NULL);
    if(status == errSecSuccess)
        emit Log("Certificate successfully imported");
    else
    {
        emit Log("Failed to import certificate: " + LogMessageForStatus(status));
    }
}

证书和私钥出现在密钥链中,如预期所示。
但是,无论是通过编程还是使用密钥链应用程序,检索证书都是一个问题。
如果我选择从密钥链中导出私钥,则会在对话框中提供以下错误信息: - "发生错误。无法导出项目。无法检索此项目的内容"
然而,如果通过双击pfx将证书和密钥添加到密钥链中,则导出密钥将按预期工作。
那么,为什么上面的代码会导致无法导出密钥的问题呢?
1个回答

1

在苹果公司的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, 
    &params, 
    keychain, 
    NULL
);

请注意params.keyAttributes的设置,它定义了可提取的密钥。

或者,可以使用较旧(已弃用)的SecKeychainItemImport API:-

BOOL                            success;
OSStatus                        err;
NSArray *                       result;
SecExternalFormat               format;
SecKeyImportExportParameters    params;
CFArrayRef                      importedItems;

result = nil;
importedItems = NULL;

format = kSecFormatPKCS12;
memset(&params, 0, sizeof(params));
params.passphrase = password;
params.keyAttributes = CSSM_KEYATTR_EXTRACTABLE;

err = SecKeychainItemImport(
   (CFDataRef) pkcs12Blob,     // importedData
   NULL,                       // fileNameOrExtension
   &format,                    // inputFormat
   NULL,                       // itemType
   0,                          // flags
   &params,                    // keyParams
   self->keychain,             // importKeychain
   &importedItems              // outItems
);
success = (err == noErr);

尽管苹果的文档中将SecKeychainItemImport函数定义为已弃用,但我被告知它不太可能很快被移除。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接