使用AFNetworking进行双向认证
1.1
1)在项目中导入证书sever.cer和AFNetworking框架:
2)然后到AFSecurityPolicy.m中重写+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode方法:

mainBundle
下的所有cer
结尾的文件并放进内存中;再一一对比。因此在代码中可以省略不写。2.6.0中,也正式将validatesCertificateChain拿掉了(https://github.com/AFNetworking/AFNetworking/blob/master/CHANGELOG.md), 其原因也同样为:There was no
documented security advantage to pinning against an entire certificate chain。
因此,在2.6.0之后,可以不管这个字段。而在此之前,从效率上来说,设定为NO会是个比较明智的选择。
1)服务端验证客户端证书,首先把服务端的证书client.p12导入到服务端的密钥库里,同时导入工程;
2)在AFURLConnectionOperation.m中加入以下方法:


为了方便,源代码附上:
#pragma mark – 自己添加的方法
-(OSStatus)extractIdentity:(CFDataRef)withP12Data:(SecIdentityRef *)identity{
OSStatus securityError = errSecSuccess;
CFStringRef password =__CFStringMakeConstantString(“123456″);
constvoid *keys[] = {kSecImportExportPassphrase};
const void *values[] = {password};
CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
securityError = SecPKCS12Import(withP12Data, options, &items);
if (securityError == 0) {
CFDictionaryRef ident = CFArrayGetValueAtIndex(items, 0);
const void *tempIdentity =NULL;
tempIdentity = CFDictionaryGetValue(ident,kSecImportItemIdentity);
*identity = (SecIdentityRef)tempIdentity;
}
if (options) {
CFRelease(options);
}
return securityError;
}
– (void)connection:(NSURLConnection *)connection
willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
NSString *thePath = [[NSBundlemainBundle] pathForResource:@”Client”ofType:@”p12″];
NSLog(@”thePaththePath == %@”,thePath);
NSData *PKCS12Data = [[NSDataalloc] initWithContentsOfFile:thePath];
CFDataRef inPKCS12Data = (__bridgeCFDataRef)PKCS12Data;
SecIdentityRef identity = NULL;
[self extractIdentity:inPKCS12Data :&identity];
SecCertificateRef certificate = NULL;
SecIdentityCopyCertificate(identity, &certificate);
const void *certs[] = {certificate};
NSURLCredential *credential = [NSURLCredentialcredentialWithIdentity:identity certificates:nilpersistence:NSURLCredentialPersistencePermanent];
[challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
}
如果是需要认证的时候不会先调用didReceiveResponse,而是先调用3)和2)的函数,NSURLAuthenticationChallenge是一个认证挑战类,也就是要求客户端进行挑战,要接收挑战也就是客户端提供挑战的凭证(用户和密码,或者客户端证书,或者信任服务器证书,或者代理),IOS提供了一个NSURLCredential的类来表示挑战凭证。可以通过如下函数来建立挑战凭证。所以访问https的时候服务器认证客户端就调用这个方法。
这两段代码是通过p12文件来验证服务器的,需要自己修改的地方只有一个,那就是2)中的CFStringRefpassword =CFSTR(“123456”);这是p12证书的密码,用自己的p12证书密码替换”123456″。
1.3控制器里如何请求
通过1.1和1.2我们的客户端和服务器双向认证已经设置好了,在控制器里只需要需要调用manager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey];的方法来进行双向认证:

然后就可以访问HTTPS的服务器了。