Как программно импортировать сертификат в цепочку для ключей моего приложения iOS и передавать идентификационные данные на сервер при необходимости?

Я работаю над приложением iOS5, которое облегчит мобильные платежи между двумя пользователями. В рамках процесса оплаты отправителю и получателю необходимо связаться с сервером. Сервер требует, чтобы обе стороны представили свои идентификационные данные, когда проверка подлинности инициируется при подключении.

В настоящее время я жестко запрограммировал процесс сертификации, используя в своем коде следующие два метода:

NSURLConnection Delegate 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;
}

Я проверял этот код много раз и добился успеха. Теперь я пытаюсь двигаться дальше и разрешить сохранение соответствующей идентификационной информации, а затем извлечь ее из цепочки для ключей приложения. Моя цель - позволить пользователям импортировать свои файлы P12 через общий доступ к файлам iTunes или Dropbox и сохранять их в связке ключей.

Я просмотрел документацию Apple по получению и использованию постоянных ссылок цепочки для ключей и не смог выяснить, как импортировать идентификационные данные. Их код немного смущает меня, так как они используют необъявленные переменные / ссылки (в частности,

&persistent_ref

переменная). Если бы кто-нибудь мог помочь расшифровать его, это было бы очень признательно.

TL; DR: как сохранить содержимое файла P12 в цепочку для ключей моего приложения iOS5 и извлечь его позже для передачи в метод NSURLConnection didReceiveAuthenticationChallenge?

2 ответа

Решение

Следующий код должен сделать трюк:

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

Вы взаимодействуете с цепочкой для ключей, передавая словарь пар ключ-значение, которые вы хотите найти или создать. Каждый ключ представляет собой параметр поиска или атрибут элемента в цепочке для ключей. Ключи - это заранее определенные константы, которые вы должны использовать в зависимости от типа данных, которые будут сохранены. Эти ключи можно найти в документе разработчика Apple.

Я думаю, что в исходном коде Apple действительно отсутствует распределение persistentRef. Они должны были добавить такую ​​декларацию в начале метода:

NSData *persistentRef = nil; 

Обратите внимание, что использование постоянной ссылки не является обязательным. Приведенный выше код должен работать просто отлично. Как Apple объясняет это хорошо:

Поскольку постоянная ссылка остается действительной между вызовами вашей программы и может быть сохранена на диске, вы можете использовать ее, чтобы упростить поиск элемента цепочки для ключей, который вам потребуется многократно

источник: https://developer.apple.com/library/ios/#documentation/Security/Conceptual/CertKeyTrustProgGuide/iPhone_Tasks/iPhone_Tasks.html#//apple_ref/doc/uid/TP40001358-CH208-DontLinkElement_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")
            }

    }
Другие вопросы по тегам