什么是双向认证呢?简而言之,就是服务器端对请求它的客户端要进行身份验证,客户端对自己所请求的服务器也会做身份验证。服务端一旦验证到请求自己的客户端为不可信任的,服务端就拒绝继续通信。客户端如果发现服务端为不可信任的,那么也中止通信。

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

上面简单介绍了一下双向认证和安全证书,那么我们现在开始正题。

首先,我们用java生成一个服务器端证书库myserverdomain和客户端证书库wenfeng.xu,取出服务器端的证书库中的证书为客户端证 书库签名并生成PKCS12格式的证书文件wenfeng.xu.pfx。然后我们将服务器端证书配置在应用服务器中,并启用客户端认证。以jetty为 例,以下为配置方法:

启动应用服务器,并用与生成服务端证书一致的域名访问应用(注意这点非常重要,ASIHTTPRequest如果不这么做是会报错的,这个域名可以随便 取,只要更改系统的host配置,让域名指向服务端ip就行了)。如果你用浏览器访问已启动的应用,如果看到以下信息,就可以开始oc客户端的编码了。

在引入了ASIHTTPRequest框架的项目中新建测试类Https.m

  1. @implementation Https
  2. + (void)testClientCertificate {
  3. NSURL *httpsUrl = [NSURL URLWithString:@"https://www.myserverdomain.com:8443/smvcj"];//访问路径
  4. ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:httpsUrl];
  5. SecIdentityRef identity = NULL;
  6. SecTrustRef trust = NULL;
  7. //绑定证书,证书放在Resources文件夹中
  8. NSData *PKCS12Data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"wenfeng.xu" ofType:@"pfx"]];//证书文件名和文件类型
  9. [Https extractIdentity:&identity andTrust:&trust fromPKCS12Data:PKCS12Data];
  10. request = [ASIHTTPRequest requestWithURL:httpsUrl];
  11. [request setClientCertificateIdentity:identity];//设定访问路径
  12. [request setValidatesSecureCertificate:NO];//是否验证服务器端证书,如果此项为yes那么服务器端证书必须为合法的证书机构颁发的,而不能是自己用openssl 或java生成的证书
  13. [request startSynchronous];
  14. NSError *error = [request error];
  15. if (!error) {
  16. NSString *response = [request responseString];
  17. NSLog(@"response is : %@",response);
  18. } else {
  19. NSLog(@"Failed to save to data store: %@", [error localizedDescription]);
  20. NSLog(@"%@",[error userInfo]);
  21. }
  22. }
  23. + (BOOL)extractIdentity:(SecIdentityRef *)outIdentity andTrust:(SecTrustRef*)outTrust fromPKCS12Data:(NSData *)inPKCS12Data {
  24. OSStatus securityError = errSecSuccess;
  25. CFStringRef password = CFSTR("p@ssw0rd888"); //证书密码
  26. const void *keys[] =   { kSecImportExportPassphrase };
  27. const void *values[] = { password };
  28. CFDictionaryRef optionsDictionary = CFDictionaryCreate(NULL, keys,values, 1,NULL, NULL);
  29. CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
  30. //securityError = SecPKCS12Import((CFDataRef)inPKCS12Data,(CFDictionaryRef)optionsDictionary,&items);
  31. securityError = SecPKCS12Import((CFDataRef)inPKCS12Data,optionsDictionary,&items);
  32. if (securityError == 0) {
  33. CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex (items, 0);
  34. const void *tempIdentity = NULL;
  35. tempIdentity = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemIdentity);
  36. *outIdentity = (SecIdentityRef)tempIdentity;
  37. const void *tempTrust = NULL;
  38. tempTrust = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemTrust);
  39. *outTrust = (SecTrustRef)tempTrust;
  40. } else {
  41. NSLog(@"Failed with error code %d",(int)securityError);
  42. return NO;
  43. }
  44. return YES;
  45. }
  46. @end

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

  1. 2014-01-04 15:49:51.194 Mac[661:303] CFNetwork SSLHandshake failed (-9807)
  2. 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)
  3. 2014-01-04 15:49:51.204 Mac[661:303] {
  4. NSLocalizedDescription = "A connection failure occurred: SSL problem (Possible causes may include a bad/expired/self-signed certificate, clock set to wrong date)";
  5. NSUnderlyingError = "Error Domain=NSOSStatusErrorDomain Code=-9807 \"The operation couldn\U2019t be completed. (OSStatus error -9807.)\" (errSSLXCertChainInvalid: Invalid certificate chain )";
  6. }

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

  1. NSMutableDictionary *sslProperties = [NSMutableDictionary dictionaryWithCapacity:1];

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

  1. NSMutableDictionary *sslProperties =[[NSMutableDictionary alloc] initWithObjectsAndKeys:
  2. [NSNumber numberWithBool:YES], kCFStreamSSLAllowsExpiredCertificates,
  3. [NSNumber numberWithBool:YES], kCFStreamSSLAllowsAnyRoot,
  4. [NSNumber numberWithBool:NO],  kCFStreamSSLValidatesCertificateChain,
  5. kCFNull,kCFStreamSSLPeerName,
  6. nil];

解决我们的错误的关键代码是

[NSNumber numberWithBool:NO],  kCFStreamSSLValidatesCertificateChain  表示不校验证书链。

保存一下再运行就可以正常访问应用了。

ASIHTTPRequest实现https双向认证请求的更多相关文章

  1. HTTPS 双向认证构建移动设备安全体系

    HTTPS 双向认证构建移动设备安全体系 对于一些高安全性要求的企业内项目,我们有时希望能够对客户端进行验证.这个时候我们可以使用Https的双向认证机制来实现这个功能. 单向认证:保证server是 ...

  2. httpd设置HTTPS双向认证

    去年用tomcat.jboss配置过HTTPS双向认证,那时候主要用的是JDK自带的keytool工具.这次是用httpd + openssl,区别比较大 在网上搜索了很多文章,发现全面介绍的不多,或 ...

  3. Android Https双向认证 + GRPC

    keywords:android https 双向认证android GRPC https 双向认证 ManagedChannel channel = OkHttpChannelBuilder.for ...

  4. nodejs之https双向认证

    说在前面 之前我们总结了https的相关知识,如果不懂可以看我另一篇文章:白话理解https 有关证书生成可以参考:自签证书生成 正题 今天使用nodejs来实现https双向认证 话不多说,直接进入 ...

  5. SpringBoot服务间使用自签名证书实现https双向认证

    SpringBoot服务间使用自签名证书实现https双向认证 以服务server-one和server-two之间使用RestTemplate以https调用为例 一.生成密钥 需要生成server ...

  6. Keytool配置 Tomcat的HTTPS双向认证

    Keytool配置 Tomcat的HTTPS双向认证 证书生成 keytool 简介 Keytool是一个Java数据证书的管理工具, Keytool将密钥(key)和证书(certificates) ...

  7. Tomcat 配置 HTTPS双向认证

    Tomcat 配置 HTTPS 双向认证指引说明: � 本文档仅提供 Linux 操作系统下的指引 � 在阅读本指引前请您在 Linux 部署 JDK 和 Tomcatserver为了 Tomcat ...

  8. Https双向认证Android客户端配置

    Https .cer证书转换为BKS证书 公式https://blog.csdn.net/zww986736788/article/details/81708967 keytool -importce ...

  9. 双向认证 HTTPS双向认证

    [微信支付]微信小程序支付开发者文档 https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=4_3 HTTPS双向认证使用说明 ...

随机推荐

  1. Mysql_mysql多个TimeStamp设置

    timestamp设置默认值是Default CURRENT_TIMESTAMP timestamp设置随着表变化而自动更新是ON UPDATE CURRENT_TIMESTAMP 但是由于 一个表中 ...

  2. PHP 常用到的一些小程序

    1.计算两个时间的相差几天 $startdate=strtotime(“2009-12-09”); $enddate=strtotime(“2009-12-05”); 上面的php时间日期函数strt ...

  3. javamail发送邮件的简单实例

    今天学习了一下JavaMail,javamail发送邮件确实是一个比较麻烦的问题.为了以后使用方便,自己写了段代码,打成jar包,以方便以后使用.呵呵 以下三段代码是我的全部代码,朋友们如果想用,直接 ...

  4. 使用Qt 开发图形界面的软件

    3DSlicer, a free open source software for visualization and medical image computing AcetoneISO:镜像文件挂 ...

  5. 关于如何用php 获取当前脚本的url

    关于用php 获取当前脚本的url很多朋友会说很简单,但是要获取很详细的就要经过多次判断哦. $PHP_TIME = time();$PHP_SELF = isset($_SERVER['PHP_SE ...

  6. POJ 1185 炮兵阵地(状压DP)

    炮兵阵地 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 26426   Accepted: 10185 Descriptio ...

  7. 在Windows下部署安装hexo

    由于hexo的文档里并没有一步步详细写出过程的细节,在Windows下又更麻烦,所以就很容易入坑. 安装 安装github for windows,msysgit 安装包: https://githu ...

  8. 用wget下载文件

    wget使用文档:https://www.gnu.org/software/wget/manual/wget.html 最开始常用的比如: wget -O  /e/movie.mp4 http://w ...

  9. jQuery 两种方法实现IE10以下浏览器的placeholder效果

    /* ** jQuery版本:jQuery-1.8.3.min.js ** 测试的浏览器:IE8,IETester下的IE6-IE9** Author:博客园小dee */ placeholder是H ...

  10. UITableview cell中多个按钮

    xib的 //不使用这种- (IBAction)button:(UIButton *)sender; //使用这种 @property (weak, nonatomic) IBOutlet UIBut ...