ASIHTTPRequest双向认证

什么是双向认证呢?简而言之,就是服务器端对请求它的客户端要进行身份验证,客户端对自己所请求的服务器也会做身份验证。服务端一旦验证到请求自己的客户端为不可信任的,服务端就拒绝继续通信。客户端如果发现服务端为不可信任的,那么也中止通信。
双向认证的算法理论是RSA,(点击此处了解RSA算法原理)。 双向认证具体又是通过安全证书的方式来实现的,安全证书可用openssl或java程序来生成,用于双向认证的安全证书中保存了密钥对,证书颁发机构信 息,签名信息,签名算法,颁发对象,有效期等信息。双向认证中安全证书分为服务器端证书和客户端证书,用服务器端证书中的私钥对客户端证书进行签名,并把 签名信息写到客户端证书中,就得到了被服务端信任的证书。当客户端请求该服务端时,服务端为拿到客户端证书信息,然后取出证书中的签名信息,用服务器端证 书的公钥验证,如果发现这个客户端证书确实是服务器端证书签名颁发的,那么通信就可以继续进行,否则中断。

上面简单介绍了一下双向认证和安全证书,那么我们现在开始正题。在引入了ASIHTTPRequest框架的项目中新建测试类Https.m

@implementation Https  

+ (void)testClientCertificate {  
    NSURL *httpsUrl = [NSURL URLWithString:@"https://www.myserverdomain.com:8443/smvcj"];//访问路径  

    ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:httpsUrl];  

    SecIdentityRef identity = NULL;  
    SecTrustRef trust = NULL;  

    //绑定证书,证书放在Resources文件夹中  
    NSData *PKCS12Data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"wenfeng.xu" ofType:@"pfx"]];//证书文件名和文件类型  
    [Https extractIdentity:&identity andTrust:&trust fromPKCS12Data:PKCS12Data];  

    request = [ASIHTTPRequest requestWithURL:httpsUrl];  

    [request setClientCertificateIdentity:identity];//设定访问路径  
    [request setValidatesSecureCertificate:NO];//是否验证服务器端证书,如果此项为yes那么服务器端证书必须为合法的证书机构颁发的,而不能是自己用openssl 或java生成的证书  


    [request startSynchronous];  

    NSError *error = [request error];  
    if (!error) {  
        NSString *response = [request responseString];  
        NSLog(@"response is : %@",response);  
    } else {  
        NSLog(@"Failed to save to data store: %@", [error localizedDescription]);  
        NSLog(@"%@",[error userInfo]);  
    }  
}  

+ (BOOL)extractIdentity:(SecIdentityRef *)outIdentity andTrust:(SecTrustRef*)outTrust fromPKCS12Data:(NSData *)inPKCS12Data {  


    OSStatus securityError = errSecSuccess;  

    CFStringRef password = CFSTR("p@ssw0rd888"); //证书密码  
    const void *keys[] =   { kSecImportExportPassphrase };  
    const void *values[] = { password };  

    CFDictionaryRef optionsDictionary = CFDictionaryCreate(NULL, keys,values, 1,NULL, NULL);  

    CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);  
    //securityError = SecPKCS12Import((CFDataRef)inPKCS12Data,(CFDictionaryRef)optionsDictionary,&items);  
    securityError = SecPKCS12Import((CFDataRef)inPKCS12Data,optionsDictionary,&items);  

    if (securityError == 0) {  
        CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex (items, 0);  
        const void *tempIdentity = NULL;  
        tempIdentity = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemIdentity);  
        *outIdentity = (SecIdentityRef)tempIdentity;  
        const void *tempTrust = NULL;  
        tempTrust = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemTrust);  
        *outTrust = (SecTrustRef)tempTrust;  
    } else {  
        NSLog(@"Failed with error code %d",(int)securityError);  
        return NO;  
    }  
    return YES;  
}  

@end  

在项目中调用 testClientCertificate方法,发现会报以下错误

2014-01-04 15:49:51.194 Mac[661:303] CFNetwork SSLHandshake failed (-9807)  
2014-01-04 15:49:51.203 Mac[661:303] Failed to save to data store: A connection failure occurred: SSL problem (Possible causes may include a bad/expired/self-signed certificate, clock set to wrong date)  
2014-01-04 15:49:51.204 Mac[661:303] {  
    NSLocalizedDescription = "A connection failure occurred: SSL problem (Possible causes may include a bad/expired/self-signed certificate, clock set to wrong date)";  
    NSUnderlyingError = "Error Domain=NSOSStatusErrorDomain Code=-9807 \"The operation couldn\U2019t be completed. (OSStatus error -9807.)\" (errSSLXCertChainInvalid: Invalid certificate chain )";  
}  

怎么会这样?分析最后一句“Invalid certificate chain” 意思是无效的证书链。因为每一个证书中都有一个证书链,来表示这个证书的层次结构。报这个错是因为这个客户端证书的最顶层是我们自己创建的证书,而不是合 法的证书机构颁发的。每个操作系统默认会把一些公认的证书机构颁发的公钥证书存在系统信认的根证书库中,以便信任由这些公认的证书机构签名给其它用户的证 书。那么如何在测试环境中避免这个错?我们只要修改ASIHTTPRequest框架中的相关配置就行了,打开ASIHTTPRequest.m文件,查 找“https”关健字,找到

NSMutableDictionary *sslProperties = [NSMutableDictionary dictionaryWithCapacity:1];  

将其注掉,然后换成以下代码

NSMutableDictionary *sslProperties =[[NSMutableDictionary alloc]
              initWithObjectsAndKeys:[NSNumber numberWithBool:YES], 
              kCFStreamSSLAllowsExpiredCertificates,  
              [NSNumber numberWithBool:YES], 
              kCFStreamSSLAllowsAnyRoot,  
              [NSNumber numberWithBool:NO], 
              kCFStreamSSLValidatesCertificateChain,  
              kCFNull,kCFStreamSSLPeerName,
              nil];  

解决我们的错误的关键代码是
[NSNumber numberWithBool:NO],kCFStreamSSLValidatesCertificateChain 表示不校验证书链。保存一下再运行就可以正常访问应用了。

转载自http://bewithme.iteye.com/blog/1999031,多谢作者分享。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值