簡體   English   中英

如何以編程方式將證書導入我的iOS應用程序的鑰匙串,並在需要時將身份傳遞給服務器?

[英]How do I programmatically import a certificate into my iOS app's keychain and pass the identity to a server when needed?

我正在開發一個iOS5應用程序,它將促進兩個用戶之間的移動支付。 作為付款流程的一部分,發件人和收件人需要與服務器通信。 服務器要求雙方在連接時啟動身份驗證質詢時顯示其身份。

目前,我在代碼中使用以下兩種方法對證書過程進行了硬編碼:

NSURLConnection委托didReceiveAuthenticationChallenge

(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:    (NSURLAuthenticationChallenge *)challenge
{
NSLog(@"Authentication challenge");

// Load Certificate
NSString *path = [[NSBundle mainBundle] pathForResource:@"PKCS12" ofType:@"p12"];
NSData *p12data = [NSData dataWithContentsOfFile:path];
CFDataRef inP12data = (__bridge CFDataRef)p12data;

SecIdentityRef myIdentity;
SecTrustRef myTrust;
extractIdentityAndTrust(inP12data, &myIdentity, &myTrust);

SecCertificateRef myCertificate;
SecIdentityCopyCertificate(myIdentity, &myCertificate);
const void *certs[] = { myCertificate };
CFArrayRef certsArray = CFArrayCreate(NULL, certs, 1, NULL);

NSURLCredential *credential = [NSURLCredential credentialWithIdentity:myIdentity certificates:(__bridge NSArray*)certsArray persistence:NSURLCredentialPersistencePermanent];

[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
}

C方法extractIdentityAndTrust

OSStatus extractIdentityAndTrust(CFDataRef inP12data, SecIdentityRef *identity, SecTrustRef *trust)
{
OSStatus securityError = errSecSuccess;

CFStringRef password = CFSTR("password");
const void *keys[] = { kSecImportExportPassphrase };
const void *values[] = { password };

CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);

CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
securityError = SecPKCS12Import(inP12data, options, &items);

if (securityError == 0) {
    CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex(items, 0);
    const void *tempIdentity = NULL;
    tempIdentity = CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemIdentity);
    *identity = (SecIdentityRef)tempIdentity;
    const void *tempTrust = NULL;
    tempTrust = CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemTrust);
    *trust = (SecTrustRef)tempTrust;
}

if (options) {
    CFRelease(options);
}

return securityError;
}

我已多次測試此代碼並取得了成功。 現在我試圖繼續並允許存儲適當的身份,然后從應用程序的鑰匙串中檢索。 我的目標是允許用戶通過iTunes文件共享或Dropbox導入他們的P12文件並將其保存到鑰匙串。

我查看了Apple關於獲取和使用持久性鑰匙串引用的文檔, 並且無法弄清楚如何導入標識。 他們的代碼對我來說有點混亂,因為他們使用未聲明的變量/引用(特別是

&persistent_ref

變量)。 如果有人可以幫助破譯它,那將非常感激。

TL; DR:如何將P12文件的內容保存到我的iOS5應用程序的鑰匙串中,並在以后檢索它以交給NSURLConnection didReceiveAuthenticationChallenge方法?

以下代碼應該可以解決問題:

NSMutableDictionary *secIdentityParams = [[NSMutableDictionary alloc] init];
[secIdentityParams setObject:(id)myIdentity forKey:(id)kSecValueRef];
OSStatus status = SecItemAdd((CFDictionaryRef) secIdentityParams, NULL);

您可以通過傳遞要查找或創建的鍵值對字典來與Keychain進行交互。 每個鍵代表一個搜索選項或鑰匙串中項目的屬性。 鍵是預定義的常量,必須根據要存儲的數據類型使用。 這些密鑰可以在Apple的開發人員文檔中找到。

我認為Apple的源代碼確實缺少persistentRef的分配。 他們應該在方法的開頭添加這樣的聲明:

NSData *persistentRef = nil; 

請注意,使用持久性引用不是強制性的。 上面的代碼應該可以正常工作。 正如Apple解釋得好:

因為持久引用在程序調用之間保持有效並且可以存儲在磁盤上,所以您可以使用一個來更容易地找到您需要重復使用的Keychain項目

來源https//developer.apple.com/library/ios/#documentation/Security/Conceptual/CertKeyTrustProgGuide/iPhone_Tasks/iPhone_Tasks.html#//apple_ref/doc/uid/TP40001358-CH208-DontLinkElementID_10

Swift 4.0

 if let url = Bundle.main.url(forResource: "XXX", withExtension: "pem") {

            let PKCS12Data = NSData(contentsOf: url)
            let inPKCS12Data = CFDataCreate(kCFAllocatorDefault, PKCS12Data!.bytes.assumingMemoryBound(to: UInt8.self), (PKCS12Data?.length)!)

            let keys: [CFString] = [kSecImportExportPassphrase]
            let values: [CFTypeRef] = []

            let keysPointer = UnsafeMutablePointer<UnsafeRawPointer?>.allocate(capacity: keys.count)
            keysPointer.initialize(to: keys)

            let valuesPointer = UnsafeMutablePointer<UnsafeRawPointer?>.allocate(capacity: values.count)
            valuesPointer.initialize(to: values)

            let optionsDictionary = CFDictionaryCreate(kCFAllocatorDefault, keysPointer, valuesPointer, 1, nil, nil)

            var items = CFArrayCreate(kCFAllocatorDefault, UnsafeMutablePointer<UnsafeRawPointer?>.allocate(capacity: 0), 0, nil)
            let securityError = SecPKCS12Import(inPKCS12Data!, optionsDictionary!, &items)
            if (securityError == 0) {
                print("Certificate installed Successfully")
            } else {
                print("Certificate installation failed")
            }

    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM