IPhone: проверка подлинности клиента HTTPS
Я сражаюсь с аутентификацией сертификата клиента. Когда серверу требуется учетная запись (в этом случае сертификат), этот метод вызывается из делегата NSURLConnection:
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
Я хочу загрузить сертификат из файла, заполнить учетные данные и запустить этот метод:
[[challenge sender] useCredential:[self credential] forAuthenticationChallenge:challenge];
Но я не знаю, как инициализировать (или заполнить) параметр SecIdentityRef. Вот мой код, который создает учетные данные:
NSString *certPath = [[NSBundle mainBundle] pathForResource:@"certificate" ofType:@"cer"];
NSData *certData = [[NSData alloc] initWithContentsOfFile:certPath];
SecIdentityRef myIdentity; // ???
SecCertificateRef myCert = SecCertificateCreateWithData(NULL, (CFDataRef)certData);
[certData release];
SecCertificateRef certArray[1] = { myCert };
CFArrayRef myCerts = CFArrayCreate(NULL, (void *)certArray, 1, NULL);
CFRelease(myCert);
NSURLCredential *credential = [NSURLCredential credentialWithIdentity:myIdentity
certificates:(NSArray *)myCerts
persistence:NSURLCredentialPersistencePermanent];
CFRelease(myCerts);
Кто-нибудь знает, как его решить? Спасибо.
Наконец-то я нашел решение, но здесь есть новая проблема:
мой клиент не отправляет сертификат на сервер. После того, как сервер запрашивает сертификат, приложение запускает этот метод:
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
и я заполняю учетные данные (как упоминалось выше), но соединение заканчивается ошибкой: NSURLErrorDomain -1206. Согласно журналам сервера сертификат клиента не отправляется приложением.
Есть ли у кого-нибудь опыт такого поведения? Нужно ли мне как-то проверить сертификат в приложении? Или что-нибудь еще, чтобы заставить его работать? Я могу предоставить свой текущий код, если это поможет. Спасибо за любые идеи...
Ответы
Ответ 1
Я использую следующие шаги:
- извлечение SecIdentityRef из файла сертификата pkcs12 с использованием функции SecPKCS12Import
- используйте функцию SecIdentityCopyCertificate для получения SecCertificateRef
а остальная часть (инициализация учетных данных) такая же, как в моем вопросе... Я могу добавить здесь больше кода, если вы хотите. Обратите внимание, что в симуляторе iphone есть ошибка (http://openradar.appspot.com/7090030), поэтому невозможно работать с большим количеством сертификатов в тренажер.
Ответ 2
Вы также можете искать идентификацию в цепочке ключей, если вы храните эту информацию там:
+ (SecIdentityRef)dumpSecIdentityRef
{
OSStatus err;
CFArrayRef result;
CFIndex resultCount;
CFIndex resultIndex;
result = NULL;
err = SecItemCopyMatching((__bridge CFDictionaryRef) [NSDictionary dictionaryWithObjectsAndKeys:
(__bridge id)kSecClassIdentity,
kSecClass, kSecMatchLimitAll,
kSecMatchLimit, kCFBooleanTrue,
kSecReturnRef, kCFBooleanTrue,
kSecReturnAttributes, nil],
(CFTypeRef *) &result);
if ((result != NULL) && (err == noErr)) {
NSMutableArray *identitiesArray = [NSMutableArray new];
resultCount = CFArrayGetCount(result);
for (resultIndex = 0; resultIndex < resultCount; resultIndex++) {
NSDictionary * thisResult;
thisResult = (__bridge NSDictionary *) CFArrayGetValueAtIndex(result, resultIndex);
NSLog(@"%@", (__bridge id)(result));
[identitiesArray addObject:thisResult];
}
CFRelease(result);
//TO DO - choose correct identity object from array.
SecIdentityRef myIdentity = (__bridge SecIdentityRef)([[identitiesArray objectAtIndex:0] valueForKey:@"v_Ref"]);
return myIdentity;
}
return nil;
}
Ответ 3
Конечно, проблема заключалась в симуляторе iPhone в xcode:) После обновления до версии 3.1 он начал работать...