16

我正在开发一个 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 方法?

4

2 回答 2

7

以下代码应该可以解决问题:

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

您通过传入要查找或创建的键值对字典与钥匙串进行交互。每个键代表一个搜索选项或钥匙串中项目的一个属性。键是预定义的常量,您必须根据要存储的数据类型使用它们。这些密钥可以在 Apple 的开发者文档中找到。

我认为Apple的源代码确实缺少persistentRef的分配。他们应该在方法的开头添加这样的声明:

NSData *persistentRef = nil; 

请注意,持久引用的使用不是强制性的。上面的代码应该可以正常工作。正如苹果公司解释得很好:

因为持久性引用在程序调用之间保持有效并且可以存储在磁盘上,所以您可以使用它来更轻松地找到您将重复需要的钥匙串项

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

于 2012-10-10T08:14:47.117 回答
0

斯威夫特 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")
            }

    }
于 2018-09-06T11:02:55.017 回答