2014-11-06 101 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定義,我已被告知,這是不可能很快地清除任何時間。