AFNetworking3.0 SSL 双向证书验证(pfx p12证书格式)

   实际开发中使用pfx格式证书进行分发,但AFSecurityPolicy工具类不支持除.cer格式外的证书,通过了解NSURLSession网络请求,其证书验证通过此NSURLSessionDelegate协议中的

- (void)URLSession:(NSURLSession *)session
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler

进行双向验证,因此可考虑从此入手。
   AFNetworking经cocopods进行管理,如果直接对AFNetworking进行修改,不利于代码管理与分发,秉着封装使用的想法,可采用继承重写协议方法实现,既能保持AFNetworking源码完整,又可不影响其它网络协议使用。代码如下:
#import 

/**
 * 用于pfx服务器证书校验
 */
@interface YKHTTPSessionManager : AFHTTPSessionManager

@property (nonatomic,copy) NSString *clientPFXName;
@property (nonatomic,copy) NSString *clientPFXPwd;

@end
#import "YKHTTPSessionManager.h"

@implementation YKHTTPSessionManager
//重写方法,保持原有方案
- (void)URLSession:(NSURLSession *)session
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler
{
    NSString *authenticationMethod = challenge.protectionSpace.authenticationMethod;
    //1. 服务器认证
    NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
    __block NSURLCredential *credential = nil;
    if ([authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        if ([self.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;
        }
        completionHandler(disposition,credential);
    }
    
    //2. 客户端认证
    if([authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPBasic] ||
       [authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPDigest] ||
       [authenticationMethod isEqualToString:NSURLAuthenticationMethodClientCertificate]){
        //失败重试3次
        if([challenge previousFailureCount] == 3){
            completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
            
        } else {
            NSURLCredential *credential = [self getCredential];
            if(credential) {
                completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
            } else {
                completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
            }
        }
    }    
}

-(NSURLCredential *)getCredential
{
    NSString *clientPFX = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:self.clientPFXName];
    NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:clientPFX];
    CFDataRef inPKCS12Data = (__bridge CFDataRef)PKCS12Data;
    
    SecIdentityRef identity = nil;
    // extract the ideneity from the certificate
    [self extractIdentity :inPKCS12Data :&identity :self.clientPFXPwd];
    
    SecCertificateRef certificate = nil;
    SecIdentityCopyCertificate (identity, &certificate);
    
    const void *certs[] = {certificate};
    CFArrayRef certArray = CFArrayCreate(kCFAllocatorDefault, certs, 1, NULL);
    // create a credential from the certificate and ideneity, then reply to the challenge with the credential
    NSURLCredential *credentialTurs = [NSURLCredential credentialWithIdentity:identity certificates:(__bridge NSArray*)certArray persistence:NSURLCredentialPersistencePermanent];
    CFRelease(certArray);
    
    return credentialTurs;
}

- (OSStatus)extractIdentity:(CFDataRef)inP12Data
                           :(SecIdentityRef*)identity
                           :(NSString*)clientPFXPassword
{
    OSStatus securityError = errSecSuccess;
    CFStringRef password = (__bridge CFStringRef)clientPFXPassword;
    const void *keys[] = { kSecImportExportPassphrase };
    const void *values[] = { password };
    
    CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
    
    CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
    securityError = SecPKCS12Import(inP12Data, 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;
}

@end

使用:

-(YKHTTPSessionManager*)afmanager{
    if(!_afmanager){
        _afmanager = [YKHTTPSessionManager manager];
        _afmanager.responseSerializer = [AFHTTPResponseSerializer serializer];
    }
    return _afmanager;
}

if(ssl){
        AFSecurityPolicy *securityPolicy =
        [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
        [securityPolicy setAllowInvalidCertificates:YES];
        self.afmanager.clientPFXName = @"xxx.pfx";
        self.afmanager.clientPFXPwd = @"xxxx";
        self.afmanager.securityPolicy = securityPolicy;
    }
    
    NSURLSessionDataTask *task = nil;
    __weak typeof(YKNetworking*) weakWorking = self;
    NSString *urlString = [NSString stringWithFormat:@"%@/%@",hostPath,funtionPath];
    if([httpMethod isEqualToString:@"POST"]){
        task = [self.afmanager POST:urlString parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
            completedBlock([weakWorking settingRequest:responseObject dataTask:task error:nil urlString:urlString params:params]);
            
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            completedBlock([weakWorking settingRequest:nil dataTask:task error:error urlString:urlString params:params]);
        }];
        
    }else{
        task = [self.afmanager GET:urlString parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
            completedBlock([weakWorking settingRequest:responseObject dataTask:task error:nil urlString:urlString params:params]);
            
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            completedBlock([weakWorking settingRequest:nil dataTask:task error:error urlString:urlString params:params]);
        }];
    }





你可能感兴趣的:(ObjC.iOS.库)