ASIHTTPRequest实现https双向认证请求

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

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

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

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

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

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

C代码  

  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("[email protected]"); //证书密码
  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方法,发现会报以下错误

C代码  

  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”关健字,找到

Java代码  

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

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

Java代码  

  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  表示不校验证书链。

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

时间: 2024-08-08 17:51:23

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

rails+apache2+passenger+ssl实现https双向认证通信

rails+apache2+passenger+ssl实现https双向认证通信 环境: 系统:Centos7 服务器:apache(httpd) 2.4.6 制作工具:openssl 1.0.1 Rails版本 :4.1.6 准备工作: 安装apache和openssl #yum install  httpd  httpd-devel httpd-tools #yum install openssl 安张mod_ssl #yum install mod_ssl 一.创建根证书 1创建CA私钥

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

HTTPS 双向认证构建移动设备安全体系 对于一些高安全性要求的企业内项目,我们有时希望能够对客户端进行验证.这个时候我们可以使用Https的双向认证机制来实现这个功能. 单向认证:保证server是真的,通道是安全的(对称密钥):双向认证:保证client和server是真的,通道是安全的(对称密钥): 要实现这么一个完整的安全体系,需要一个CA或者openssl自建CA来管理签发客户端证书.作为项目要求的场景可能是这样的,一个前端网站专门用于签发证书,通过电子邮件发送下载客户端证书邮件到移动

nginx与ios实现https双向认证

服务端配置 nginx关键配置如下: listen 443; server_name localhost; ssl on; ssl_certificate /usr/local/opt/nginx/certificates/server.cer; ssl_certificate_key /usr/local/opt/nginx/certificates/server.key.pem; ssl_client_certificate /usr/local/opt/nginx/certificates

Android Https双向认证 + GRPC

keywords:android https 双向认证android GRPC https 双向认证 ManagedChannel channel = OkHttpChannelBuilder.forAddress("xxx",yyy) .overrideAuthority("zzz") .sslSocketFactory(sslFactory) .build(); 1.千万不要像官网案例那样设置setPlaintext(true),这个是设置明文,我们用的是密文

iOS ASIHTTPRequest用https协议加密请求

iOS 终端请求服务端数据时,为了保证数据安全,我们一般会使用https协议加密,而对于iOS的网络编程,我们一般会使用开源框架:ASIHTTPRequest,但是如果使用传统的http方式,即使忽略验证的话,程序也会报[error-9844]的错误,具体错误如下描述: [Error Domain=ASIHTTPRequestErrorDomain Code=1 "A connection failure occurred" UserInfo=0x6aafa30 {NSUnderlyi

利用tomcat服务器配置https双向认证

首先请保证已经安装好jdk,并且环境变量以及配置好了 第一步.为服务器生成证书: 使用toolkey为tomcat生成证书,假定目标机器的域名为localhost,使用如下命令生成:keytool –genkey –v –aliaslocalhost_server RSA –keystore localhost_server.store  –validity 36500 第二步.为客户端生成证书: 为浏览器生成证书,以便让服务器来验证它.为了能保证证书顺利导入至IE和Firefox,证书格式应该

tomcat https双向认证

没啥可写的,直接看这些博文吧... 注:server.xml 双向认证 注意得配:truststoreFile,单向不用 浏览器客户端p12证书,需要添加到服务器的jks文件中. http://www.blogjava.net/stevenjohn/archive/2012/08/22/385989.html http://www.360doc.com/content/10/0401/23/633992_21237818.shtml http://www.blogjava.net/stevenj

tomcat构建HTTPS双向认证

第一步:为服务器生成证书 # keytool -genkey -alias tomcat -keyalg RSA -keystore /usr/local/ac/web/tomcat.keystore -validity 36500 (参数简要说明:"/etc/tomcat.keystore"含义是将证书文件保存在路径/usr/local/ac/web/下,证书文件名称是tomcat.keystore :"-validity 36500"含义是证书有效期,36500

AFNetWorking https 双向认证

客户端验证服务端证书: 需要http配置路径需要域名 1:先项目中倒入服务端证书 sever.cer, 2.然后设置 AFSecurityPolicy self.manager = [AFHTTPRequestOperationManager manager]; self.manager.responseSerializer = [[AFHTTPResponseSerializer alloc] init]; [self.manager.requestSerializer setValue:@"