Как я могу программно импортировать сертификат в брандмауэр приложения для 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?
Ответы
Ответ 1
Следующий код должен сделать трюк:
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:
Поскольку постоянная ссылка остается в силе между вызовами ваша программа и может быть сохранена на диске, вы можете использовать ее для ее создания легче найти элемент брелка, который вам понадобится повторно
источник: https://developer.apple.com/library/ios/#documentation/Security/Conceptual/CertKeyTrustProgGuide/iPhone_Tasks/iPhone_Tasks.html#//apple_ref/doc/uid/TP40001358-CH208-DontLinkElementID_10