配置Https:
(一)准备证书
.cer (后端提供,有可能是crt,直接改后缀为cer就行)
.p12 (后端给过来的pfx证书,里面包含公钥私钥,把证书导入钥匙串,然后导出为.p12文件,带密码)
(二)检查证书
1.检查是否符合,把证书拉入项目根目录,点击就可以查看相关信息
2.打开终端输入 nscurl —ats-diagnostics —verbose https://你的域名/
然后会出现类似这样的反馈,分别有TLSv1.0----TLSv1.2的测试案例返回,如果HTTPS服务器能通过ATS特性,则上面所有测试案例都是PASS;如果某一项的Reuslt是FAIL,就找到ATS Dictionary来查看,就能知道HTTPS服务器不满足ATS哪个条件。
3.然后根据测试案例TLSv1.2返回的NSExceptionDomains信息配置项目的根.plist文件的App Transport Security Settings->Exception Domains->
【图仅供示例,请根据自己的返回填写】
(三)代码设置,双向认证
{ //manager自行配置 AFHTTPSessionManager manager = nil; if ([self baseUrl] != nil) { manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:[self baseUrl]]]; } else { manager = [AFHTTPSessionManager manager]; } manager.securityPolicy = [self getSecurityPolicy]; [manager setSessionDidBecomeInvalidBlock:^(NSURLSession * _Nonnull session, NSError * _Nonnull error) { NSLog(@"setSessionDidBecomeInvalidBlock"); }]; //客服端请求验证 重写 setSessionDidReceiveAuthenticationChallengeBlock 方法 __weak typeof(self)weakSelf = self; [manager setSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSessionsession, NSURLAuthenticationChallenge *challenge, NSURLCredential __autoreleasing_credential) { NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling; __autoreleasing NSURLCredential *credential =nil; if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { if([weakSelf.manager.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) { credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; if(credential) { disposition =NSURLSessionAuthChallengeUseCredential; } else { disposition =NSURLSessionAuthChallengePerformDefaultHandling; } } else { disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge; } } else { // client authentication SecIdentityRef identity = NULL; SecTrustRef trust = NULL; //后端给过来的pfx证书导入钥匙串,然后导出为.p12文件,名字随意。示例为:client.p12 NSString *p12 = [[NSBundle mainBundle] pathForResource:@"client" ofType:@"p12"]; NSFileManager fileManager =[NSFileManager defaultManager]; if(![fileManager fileExistsAtPath:p12]) { NSLog(@"client.p12:not exist"); } else { NSData PKCS12Data = [NSData dataWithContentsOfFile:p12]; if ([[weakSelf class] extractIdentity:&identity andTrust:&trust fromPKCS12Data:PKCS12Data]) { SecCertificateRef certificate = NULL; SecIdentityCopyCertificate(identity, &certificate); const voidcerts[] = {certificate}; CFArrayRef certArray =CFArrayCreate(kCFAllocatorDefault, certs,1,NULL); credential =[NSURLCredential credentialWithIdentity:identity certificates:(__bridge NSArray)certArray persistence:NSURLCredentialPersistencePermanent]; disposition =NSURLSessionAuthChallengeUseCredential; } } } _credential = credential; return disposition; }];}+(BOOL)extractIdentity:(SecIdentityRef)outIdentity andTrust:(SecTrustRef )outTrust fromPKCS12Data:(NSData )inPKCS12Data { OSStatus securityError = errSecSuccess; //client certificate password NSDictionaryoptionsDictionary = [NSDictionary dictionaryWithObject:@"p12证书密码" forKey:(__bridge id)kSecImportExportPassphrase]; CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL); securityError = SecPKCS12Import((__bridge CFDataRef)inPKCS12Data,(__bridge CFDictionaryRef)optionsDictionary,&items); if(securityError == 0) { CFDictionaryRef myIdentityAndTrust =CFArrayGetValueAtIndex(items,0); const voidtempIdentity =NULL; tempIdentity= CFDictionaryGetValue (myIdentityAndTrust,kSecImportItemIdentity); outIdentity = (SecIdentityRef)tempIdentity; const voidtempTrust =NULL; tempTrust = CFDictionaryGetValue(myIdentityAndTrust,kSecImportItemTrust); outTrust = (SecTrustRef)tempTrust; } else { NSLog(@"Failedwith error code %d",(int)securityError); return NO; } return YES;}+ (AFSecurityPolicy)getSecurityPolicy{ NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"cer证书名字" ofType:@"cer"]; NSData *certData = [NSData dataWithContentsOfFile:cerPath]; NSSet *certSet = [NSSet setWithObject:certData]; AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate]; policy.allowInvalidCertificates = YES; policy.validatesDomainName = NO; policy.pinnedCertificates = certSet; /**** SSL Pinning ****/ return policy;}
最近在配置https,使用的是AFNetWorking3.0。
一直报个NSArray object nil 闪退,开始找了项目本身的问题,一直找不到。
后来发现,是AFNetWorking里AFSecurityPolicy.m文件中的方法
(BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain,代码片段里
解决方法:
1.将后端发过来的.crt证书,修改后缀.cer,导入钥匙串
2.再从钥匙串导出该证书,拉到项目里直接使用