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

双向认证的算法理论是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. 什么是J2EE,包括哪些规范!

    J2EE平台由一整套服务(Services).应用程序接口(APIs)和协议构成,它对开发基于Web的多层应用提供了功能支持,下面对J2EE中的13种技术规范进行简单的描述(限于篇幅,这里只能进行简单 ...

  2. QPushButton 与 QListWidget 的按键响应

    在Qt中添加按钮或表格控件时需要添加其按键响应,一般来说有两种方法,一种是直接实现其响应函数,第二种是自己写一个响应函数,然后用Qt的信号槽将它们连接起来.愚以为第一种方法更为简单一些. 声明这些控件 ...

  3. NodeJs - 100

    Nodejs官方文档 https://nodejs.org/en/docs/ Nodejs官方网站 https://nodejs.org/en/ Nodejs的特征:  1.采用非阻塞性IO机制:—— ...

  4. 【液晶模块系列基础视频】5.1X-GUI字体驱动1

    ============================= 技术论坛:http://www.eeschool.org 博客地址:http://xiaomagee.cnblogs.com 官方网店:ht ...

  5. 【iCore2双核心板】SRAM 读写实验(基于Verilog语言)

    _____________________________________ 深入交流QQ群: A: 204255896(1000人超级群,可加入) B: 165201798(500人超级群,满员) C ...

  6. POJ 3628 Bookshelf 2(01背包)

    Bookshelf 2 Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9488   Accepted: 4311 Descr ...

  7. multipart/form-data请求与文件上传

    要上传文件,需要用post方法,并且设置enctype为multipart/form-data. <form action="/upload" method="po ...

  8. mongodb 手动分片的命令汇总

    手动分片的操作 自动分片会带来性能的下降. 所以要合理使用手动分片. 并且配合Tag一起使用. # 对于4个shard的程序, 预先处理的指令1. 加入分片服务器sh.addShard( " ...

  9. twitter storm源码走读之2 -- tuple消息发送场景分析

    欢迎转载,转载请注明出处源自徽沪一郎.本文尝试分析tuple发送时的具体细节,本博的另一篇文章<bolt消息传递路径之源码解读>主要从消息接收方面来阐述问题,两篇文章互为补充. worke ...

  10. Redis 笔记与总结7 PHP + Redis 信息管理系统(用户信息的增删改查)

    1. PHP 连接 Redis 访问 redis 官方网站的 client 栏目:http://www.redis.io/clients#php,可以获取 redis 的 php 扩展. 其中 php ...