Я в тупике: моему приложению необходимо подключиться к серверу, который использует самозаверяющие сертификаты для HTTPS и требует аутентификации на стороне клиента. Хуже того, мне действительно нужен медиаплеер iOS для подключения к этому серверу, поэтому я следовал инструкция для этого в письме:
credential = [NSURLCredential credentialWithIdentity:identity certificates:certs persistence:NSURLCredentialPersistenceForSession];
NSURLProtectionSpace *space = [[NSURLProtectionSpace alloc] initWithHost:@"server.com"
port:0
protocol:NSURLProtectionSpaceHTTPS
realm:nil
authenticationMethod:NSURLAuthenticationMethodClientCertificate];
[[NSURLCredentialStorage sharedCredentialStorage] setDefaultCredential:credential forProtectionSpace:space];
Но это просто не сработает. Поэтому я попытался сделать запрос на сервер вручную:
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://server.com"]
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(@"Done : %@", error ? error : @"OK");
}];
все, что я получаю, это эта ошибка:
2016-06-13 08:22:37.767 TestiOSSSL[3172:870700] CFNetwork SSLHandshake failed (-9824 -> -9829)
2016-06-13 08:22:37.793 TestiOSSSL[3172:870700] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9829)
2016-06-13 08:22:37.815 TestiOSSSL[3172:870685] Done : Error Domain=NSURLErrorDomain Code=-1206 "The server “ server.com” requires a client certificate." UserInfo={NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x13de519b0>, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9829, NSUnderlyingError=0x13de4f280 {Error Domain=kCFErrorDomainCFNetwork Code=-1206 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=1, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x13de519b0>, _kCFNetworkCFStreamSSLErrorOriginalValue=-9829, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9829, kCFStreamPropertySSLPeerCertificates=<CFArray 0x13dda0a70 [0x1a0dc2150]>{type = immutable, count = 2, values = (
0 : <cert(0x13dda4970) s: Server.com i: Localhost CA>
1 : <cert(0x13dda50d0) s: Localhost CA i: Localhost CA>
)}}}, NSErrorPeerCertificateChainKey=<CFArray 0x13dda0a70 [0x1a0dc2150]>{type = immutable, count = 2, values = (
0 : <cert(0x13dda4970) s: Server.com i: Localhost CA>
1 : <cert(0x13dda50d0) s: Localhost CA i: Localhost CA>
)}, NSLocalizedDescription=The server “server.com” requires a client certificate., NSErrorFailingURLKey=https://server.com/, NSErrorFailingURLStringKey=https://server.com/, NSErrorClientCertificateStateKey=1}
Теперь, если я настрою свой собственный NSURLSession и использую обратный вызов URLSession:didReceiveChallenge:completionHandler::
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
theSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
NSURLSessionDataTask *task = [theSession dataTaskWithURL:[NSURL URLWithString:@"https://server.com"]
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(@"Done : %@", error ? error : @"OK");
}];
а потом:
- (void)URLSession:(NSURLSession *)session
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition,
NSURLCredential *credential))completionHandler
{
NSLog(@"Asking for credential");
NSURLCredential *conf = [session.configuration.URLCredentialStorage defaultCredentialForProtectionSpace:challenge.protectionSpace];
completionHandler(NSURLSessionAuthChallengeUseCredential, conf);
}
Обратите внимание, как я использую [session.configuration.URLCredentialStorage defaultCredentialForProtectionSpace:challenge.protectionSpace], что, как я полагаю, делает реализация NSURLSession по умолчанию, когда получает запрос аутентификации.
Это работает для этого конкретного соединения! Это доказывает, что учетные данные в порядке и что они правильно зарегистрированы в качестве учетных данных по умолчанию в NSURLCredentialStorage по умолчанию.
Но любое решение, связанное с обратным вызовом didReceiveChallenge:, бесполезно, потому что я не могу контролировать, какой NSURLSession использует медиаплеер.
Я пробовал взломать CustomHTTPProtocol, и это не помогло. тоже не работает.
Любое предложение? Я просмотрел все подобные сообщения на SO, я не могу найти решение для этого. Этот пост действительно близок, но принятый ответ не имеет смысла для меня и явно противоречит документации Apple.