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

原创 2016年08月31日 14:41:52

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

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

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

/**
 * 用于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]);
        }];
    }





相关文章推荐

BouncyCastle产生一个PKCS#12规范的PFX/p12证书【自用笔记】

RT,在C#中实现,依赖.netFramework2.0   BouncyCastle中提供了PKCS12Store,Pkcs12StoreBuilder,AsymmetricKeyEntry,X...
  • cuoban
  • cuoban
  • 2016年01月25日 16:54
  • 1547

webview的自定义SSL认证配置(p12证书)

因为网页中要用到自定义SSL证书,而且密钥是 xxx.p12, 我们是将密钥转化为byte[]的形式传进来的,传入密码,这样来处理SSL 关键在onReceivedClientCertRequest...
  • zoeice
  • zoeice
  • 2013年11月01日 10:01
  • 6157

p12格式数字证书

  • 2015年05月28日 21:41
  • 2KB
  • 下载

ios AFNetworking https 双向证书验证实现

因为公司对接口做了安全处理,部分接口实现https 加密,双向验证就是 ,服务端要验证客户端,客户端也要验证服务器端,通过证书验证首先,因为用的是AFNetworking实现的网络请求,已经自带htt...

p12格式的安全证书在Java项目中使用

前一段时间因为需要别人给的p12格式的安全证书才能获取相关数据,但是p12格式的证书无法导入到jdk的证书库,但是又需要在Java项目中使用p12格式的证书,找了很久,最后在别人的帮助下找到方法。 因...

<iOS常见问题>之苹果证书无法导出p12格式的文件

本文介绍了苹果证书无法导出p12格式的文件的解决方法.一.打开钥匙串导出证书的默认界面,发现p12选项为灰色,无法选择.说明: 我对这种情况的证书进行测试,将直接导出.cer的证书,拷贝到其他电脑上...

SSL证书转换(JKS、PFX)

package com.hengbao; import java.io.FileInputStream; import java.io.FileNotFoundException; impo...

SSL双向认证证书制作过程流程

  • 2016年07月07日 13:56
  • 2.39MB
  • 下载

android ssl双向验证 X509证书信任管理器类的实现及应用

在JSSE中,证书信任管理器类就是实现了接口X509TrustManager的类。我们可以自己实现该接口,让它信任我们指定的证书。   接口X509TrustManager有下述三个公有的方法需...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:AFNetworking3.0 SSL 双向证书验证(pfx p12证书格式)
举报原因:
原因补充:

(最多只允许输入30个字)