2014-11-06 133 views
2

我有一个客户端获取的证书(.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)); 
    } 
} 

证书和私钥如期出现在钥匙串中。

但是,试图以编程方式或使用Keychain应用程序尝试检索证书是一个问题。

如果我选择要导出从钥匙串中的私钥,我具备在一个对话框下面的错误: - 。

“时发生错误无法导出的项目内容。此项目不能被检索”

然而,如果证书和密钥的PFX添加到钥匙串通过双击,出口重点工程如预期。

那么,为什么上面的代码会导致无法导出密钥的问题呢?

回答

0

在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, 
    &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定义,我已被告知,这是不可能很快地清除任何时间。