Android客户端 - Restlet 2.0.15 - 无法连接HTTPS / SSL - 可恢复错误1001

时间:2013-05-02 18:22:47

标签: android ssl https restlet

我使用Android的Restlet框架(2.0.15)编写了一个Android Web服务客户端,我还编写了Web服务后端(再次使用Restlet 2.0.15 JEE),已经上传到AWS Elastic Beanstalk(因此客户端调用将采用“http://my_web_service.elasticbeanstalk.com/this/is/my/request”的形式)。一切都在HTTP上工作正常,所以现在我想用HTTPS替换它,但事实证明这比我最初想的更难。

我已经从Comodo创建了一个试用版SSL证书,我已经在其中声明了我拥有的域名(不幸的是,我无法声明运行AWS负载均衡器的elasticbeanstalk.com子域名作为证书)主机名)。此证书已上传到我的AWS实例,它似乎正在运行(通过Web浏览器测试,在我接受浏览器上的证书后,成功完成了几个https调用)。我不喜欢这个证书的唯一一件事就是我得到一个警告,这可能是一个无效的证书,因为声明的主机名(我的域名)和证书运行的实际主机名(elasticbeanstalk.com)不匹配。

在我的客户端我正在使用apache http客户端(已经在claspath上加载了org.apache.httpclient.jar),这就是我创建每次调用时使用的客户端资源的方式,这很简单:

ClientResource resource = new ClientResource(resourceUri);
    Engine.getInstance().getRegisteredClients().clear();
Engine.getInstance().getRegisteredClients().add(new HttpClientHelper(null));

当然,resourceUri采用“https://my_web_service.elasticbeanstalk.com/this/is/my/request”的形式,这是工作HTTP案例和非工作HTTPS案例之间的唯一区别。 使用HTTPS,我收到以下错误:

检测到可恢复的错误(1001),再次尝试2000毫秒。

我尝试了一些我在google上找到的建议(使用org.restlet.ext.net httpclient而不是apache,甚至从Restlet Android 2.1加载org.restlet.ext.ssl jar),但没有任何效果如此远。 我甚至用Wireshark捕获了网络跟踪,这是调用流程:

|Time     | 192.168.2.111                         |
|         |                   | 54.245.249.149    |                   
|14.769   |         65430 > https [SYN]           |TCP: 65430 > https [SYN] Seq=0 Win=65535 Len=0 MSS=1460 WS=16 TSval=3906214190 TSecr=0 SACK_PERM=1
|         |(65430)  ------------------>  (443)    |
|15.026   |         https > 65430 [SYN,           |TCP: https > 65430 [SYN, ACK] Seq=0 Ack=1 Win=14480 Len=0 MSS=1452 SACK_PERM=1 TSval=758478734 TSecr=3906214190 WS=256
|         |(65430)  <------------------  (443)    |
|15.027   |         65430 > https [ACK]           |TCP: 65430 > https [ACK] Seq=1 Ack=1 Win=132480 Len=0 TSval=3906214442 TSecr=758478734
|         |(65430)  ------------------>  (443)    |
|15.034   |         Client Hello                  |TLSv1: Client Hello
|         |(65430)  ------------------>  (443)    |
|15.289   |         https > 65430 [ACK]           |TCP: https > 65430 [ACK] Seq=1 Ack=124 Win=14592 Len=0 TSval=758478799 TSecr=3906214448
|         |(65430)  <------------------  (443)    |
|15.291   |         Server Hello, Certi           |TLSv1: Server Hello, Certificate, Server Hello Done
|         |(65430)  <------------------  (443)    |
|15.291   |         65430 > https [ACK]           |TCP: 65430 > https [ACK] Seq=124 Ack=1386 Win=131088 Len=0 TSval=3906214696 TSecr=758478799
|         |(65430)  ------------------>  (443)    |
|17.207   |         Client Key Exchange           |TLSv1: Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message
|         |(65430)  ------------------>  (443)    |
|17.505   |         Encrypted Handshake           |TLSv1: Encrypted Handshake Message, Change Cipher Spec, Encrypted Handshake Message
|         |(65430)  <------------------  (443)    |
|17.505   |         Client Hello                  |TLSv1: Client Hello
|         |(65430)  ------------------>  (443)    |
|17.507   |         65430 > https [FIN,           |TCP: 65430 > https [FIN, ACK] Seq=557 Ack=1636 Win=130832 Len=0 TSval=3906216837 TSecr=758479353
|         |(65430)  ------------------>  (443)    |
|17.776   |         Encrypted Alert               |TLSv1: Encrypted Alert
|         |(65430)  <------------------  (443)    |
|17.776   |         65430 > https [RST]           |TCP: 65430 > https [RST] Seq=557 Win=0 Len=0
|         |(65430)  ------------------>  (443)    |
|17.777   |         Encrypted Alert               |TLSv1: Encrypted Alert
|         |(65430)  <------------------  (443)    |
|17.777   |         https > 65430 [FIN,           |TCP: https > 65430 [FIN, ACK] Seq=1682 Ack=557 Win=15616 Len=0 TSval=758479421 TSecr=3906216836
|         |(65430)  <------------------  (443)    |
|17.777   |         https > 65430 [ACK]           |TCP: https > 65430 [ACK] Seq=1683 Ack=558 Win=15616 Len=0 TSval=758479421 TSecr=3906216837
|         |(65430)  <------------------  (443)    |
|17.777   |         65430 > https [RST]           |TCP: 65430 > https [RST] Seq=557 Win=0 Len=0
|         |(65430)  ------------------>  (443)    |
|17.777   |         65430 > https [RST]           |TCP: 65430 > https [RST] Seq=557 Win=0 Len=0
|         |(65430)  ------------------>  (443)    |
|17.777   |         65430 > https [RST]           |TCP: 65430 > https [RST] Seq=558 Win=0 Len=0
|         |(65430)  ------------------>  (443)    |

从上面的调用流程来看,似乎客户端和服务器无法完成成功的协商,但我不知道为什么。

欢迎任何有关如何解决此问题的建议。我认为问题存在于客户端(使用Restlet 2.0.15框架的Android应用程序),但不是应用程序代码本身(因为在使用HTTP时一切正常),而是在实际进行任何调用之前进行SSL协商/握手。我也相信证书颁发机构(Comodo)已被Android成功接受/信任(我已经通过Android设备浏览器完成了https调用),但它仍然会在继续之前向您提供证书警告您需要接受。可能是Restlet 2.0.15无法顺利处理SSL通信,我需要升级到2.1或更高版本吗?

期待听到您的建议。 如果您想获得更多可以提供帮助的信息,请问我。 :)

提前致谢, 亚历

=========更新=========

好的,就像我怀疑的那样。问题是证书(具有CNAME = www .mydomain.com,但是从https:// mywebservice.mlasticbeanstalk.com加载)似乎对Android客户端无效,因此它甚至不发送GET / POST请求服务器。

当我从终端发送POST方法(使用“curl”)时,我意识到了这一点,忽略了ssl验证警告(-k选项)。这次安全连接按预期响应,发送回json回复。

根据Google自己的Android文档建议,我尝试更改HostnameVerifier方法,以便通过认证验证。这就是我的ClientResource当前的创建方式:

public static ClientResource createClientResource(String resourceUri) {
    Reference reference = new Reference(resourceUri);
    System.setProperty("ssl.TrustManagerFactory.algorithm",javax.net.ssl.KeyManagerFactory.getDefaultAlgorithm());

    org.restlet.Context context = new org.restlet.Context();
    context.getAttributes().put("hostnameVerifier", new HostnameVerifier() {

                    @Override
                    public boolean verify(String arg0, SSLSession arg1) {
                            return true;

                    }

            });

    ClientResource resource = new ClientResource(context, reference);

    Engine.getInstance().getRegisteredClients().clear();
    Engine.getInstance().getRegisteredClients().add(new HttpClientHelper(null));
    Engine.getInstance().getRegisteredConverters().add(0, new JacksonConverter());

    resource.release();

    return resource;
}

但这也不起作用,我仍然得到1001可恢复的错误。但是,Android客户端无法通过“无效”请求。

我非常感谢任何建议。 :)

1 个答案:

答案 0 :(得分:0)

我终于设法解决了这个问题。 检查“响应”对象后,更具体地说是响应状态,这是错误引发的异常:

Communication Error (1001) - The connector failed to complete the communication with the server
javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor  for certification path not found.

这使我重新调查我在AWS上传的证书,这正是问题所在。似乎我没有在AWS EC2实例上正确安装证书链(中间证书)。我的CA的证书链由4个证书文件组成,AWS需要以非常特定的顺序(首先签署证书,最后签署CA根证书,以及之间的所有其他证书),以pem / text格式给出。

在纠正证书链后,一切都像魅力一样。 :)