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

双向认证的算法理论是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. 基于开源Dubbo分布式RPC服务框架的部署整合

    一.前言 Dubbo 作为SOA服务化治理方案的核心框架,用于提高业务逻辑的复用.整合.集中管理,具有极高的可靠性(HA)和伸缩性,被应用于阿里巴巴各成员站点,同时在包括JD.当当在内的众多互联网项目 ...

  2. winform学习2-datagridview数据绑定

    1.datagridview.clearSelection()清除默认的选中项 2.列数据显示,首先列必须是显示状态, 3.布局-单元格内文字内容居中显示,示例:外观-defaultCellStyle ...

  3. iOS开发项目之四 [ 调整自定义tabbar的位置与加号按钮的位置]

    自定义tabbar与按钮的添加 01 - 把系统的tabbar用我们自己的覆盖 LHQTabBar *lhqTabBar = [[LHQTabBar alloc]init]; [self setVal ...

  4. iOS开发项目之三 [ 自定义tabBarCtrl]

    01 让tabBar的图片保持原样.图片渲染的处理 ctrl.tabBarItem.selectedImage = [[UIImage imageNamed:[NSString stringWithF ...

  5. Android Studio 想说爱你不容易

    开始使用Android Studio 真是非常痛苦的一段经历,而这一切的根源就在于GFW,俗称“墙” 如果避过墙来安装 AS,其实我已经在另外一篇文章中说明:http://www.cnblogs.co ...

  6. 清除行内元素之间HTML空白的几种解决方案

    行内块(inline-block)是非常有用的,特别是想要不用'block'和'float'来控制这些行内元素的margin,padding之时. 问题来了,HTML源码中行内元素之间的空白有时候显示 ...

  7. CSS权威指南 - 基础视觉格式化 2

    行内元素 em a 非替换元素 img 替换元素 两者在内联内容处理方式不一样. inline有时候被翻译成内联,比如inline content,有时候被翻译成行内 inline box. 行布局 ...

  8. 《Java核心技术卷二》笔记(三)正则表达式

    正则表达式语法 一个正则表达式描述了字符串的构成规则(模式).如果一个具体的字符串正好符合正则表达式描述的这个规则,这个字符串就是与表达式匹配的.先看一下怎么描述这种规则,也就是正则表达式语法.正则表 ...

  9. maven-surefire-plugin总结

    Maven通过Maven Surefire Plugin插件执行单元测试.(通过Maven Failsafe Plugin插件执行集成测试) 在pom.xml中配置JUnit,TestNG测试框架的依 ...

  10. a标签属性说明

    语法 <a target="value" href="url" > varlue:值. _blank:在新窗口中打开被链接文档. _self:默认. ...