我被难住了:我的应用程序需要连接到一个服务器,该服务器使用HTTPS的自签名证书,并需要客户端身份验证。更糟糕的是,我实际上需要iOS媒体播放器来连接那个服务器,所以我严格遵循了苹果的instruction:
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);
}注意我是如何使用defaultCredentialForProtectionSpace:challenge.protectionSpace,session.configuration.URLCredentialStorage的,我认为这就是NSURLSession的默认实现在收到身份验证质询时所做的事情。
对于这个特殊的连接,这是可行的!这证明该凭证是OK的,并且它被正确地注册为默认NSURLCredentialStorage中的默认凭证。
但是任何依赖于didReceiveChallenge:回调的解决方案都不是很好,因为我无法控制媒体播放器使用的是哪个NSURLSession。
我尝试过CustomHTTPProtocol攻击,但也不起作用。
有什么建议吗?我已经看过了所有类似的帖子,所以我找不到解决这个问题的办法。这款post确实很接近,但公认的答案对我来说毫无意义,而且显然与苹果的文档相矛盾。
发布于 2016-07-25 13:30:41
尽管在默认会话和NSURLConnection之间共享了许多功能,但显然这部分功能不是这样的。
另一种可能性是请求发生在单独的任务中,在这种情况下,可能不可能以您正在尝试的方式完成它,因为它将涉及不同的共享会话。如果是这种情况,您可能必须自己将凭据存储到密钥链中,并相信其他进程将共享密钥链并正确获取凭据。
https://stackoverflow.com/questions/37783314
复制相似问题