本文节选自
https://gist.github.com/JacksonTian/5855751
一般而言HTTP和HTTPS都不会遇到这个问题,只要实现NSURLConnectionDataDelegate
协议就能完成需求。但是对于自签名证书,NSURLConnection
对象无法验证服务端证书的真伪。这个时候需要动用到NSURLConnectionDelegate
协议。
具体方法是以下几个:
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)prote
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
canAuthenticateAgainstProtectionSpace
如果返回No,将由系统自行处理。返回YES将会由后续的
didReceiveAuthenticationChallenge
处理。默认为No。
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{
NSLog(@"处理证书");
return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}
在
didReceiveAuthenticationChallenge
中我们要通过
challenge
的
sender
告知是否信任服务端的证书。
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
if (trusted) {
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
} else {
[challenge.sender cancelAuthenticationChallenge:challenge];
}
}
我们可以设定trusted
来判定是否信任。可以直接设置为YES来表示信任服务端。但是直接设置是不严谨的,并没有验证服务端证书的真伪。
在连接建立后,我们可以拿到服务端的证书。要验证它的真伪需要我们用CA的证书来进行判定。
// 获取der格式CA证书路径
NSString *certPath = [[NSBundle mainBundle] pathForResource:@"ca" ofType:@"der"];
// 提取二进制内容
NSData *derCA = [NSData dataWithContentsOfFile:certPath];
// 根据二进制内容提取证书信息
SecCertificateRef caRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)derCA);
// 形成钥匙链
NSArray * chain = [NSArray arrayWithObject:(__bridge id)(caRef)];
caChainArrayRef = CFBridgingRetain(chain);
// 取出服务器证书
SecTrustRef trust = [[challenge protectionSpace] serverTrust];
SecTrustResultType trustResult = 0;
// 设置为我们自有的CA证书钥匙连
int err = SecTrustSetAnchorCertificates(trust, caChainArrayRef);
if (err == noErr) {
// 用CA证书验证服务器证书
err = SecTrustEvaluate(trust, &trustResult);
}
CFRelease(trust);
// 检查结果
BOOL trusted = (err == noErr) && ((trustResult == kSecTrustResultProceed)||(trustResult == kSecTrustResultConfirm) || (trustResult == kSecTrustResultUnspecified));
UIWebView不能处理自签名的证书,需要在它发起访问之前通过上述的方法进行证书的设置判定,之后再通过UIWebView进行访问即可通过。
延伸阅读: