一次SSLPeerUnverifiedException,SSLHandshakeException的问题分析
最近工作遇到一个https链接,通过pc(浏览器,curl)能正常访问,ios能正常访问,但是在android里访问异常
使用DefaultHttpClient访问
javax.net.ssl.SSLPeerUnverifiedException: No peer certificate
使用AndroidHttpClient访问
javax.net.ssl.SSLHandshakeException: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate: Certificate not valid until Tue Jun 07 08:00:00 GMT+08:00 2016 (compared to Tue May 03 22:25:19 GMT+08:00 2016)
通过抓包发现
pc访问,服务器返回了正确的证书,所以访问正常
抓包工具是'Wireshark 2.0.4 Intel 64.dmg’
https://www.wireshark.org/download/osx/all-versions/
android访问,返回了错误的证书,所以访问不正常
抓包工具:tcpdump: http://www.androidtcpdump.com/
通过比较pc,android与服务器的tls协议交互,
发现tls版本不同,pc使用tlsv1.2 android使用tls1
pc的client hello 协议中包含server_name字断,而android的client hello协议中没有
原因分析:
经过咨询运维同学后,得出结论android上的httpclient没有支持sni,sni(Server Name Indication)是个什么东西呢
这篇文件讲的很清楚了http://fengchj.com/?p=2302,各位看官可以去仔细看看。简单讲就是,同一个机器的同一个的端口上配置了两个https站点,需要通过server_name判断它访问的是哪一个站点,然后返回相应的证书。
解决办法:
这篇文章写的很清楚,
http://blog.dev001.net/post/67082904181/android-using-sni-and-tlsv12-with-apache
简单说就是调用setHostName方法,添加相应的hostname。笔者也正是通过这个方式解决的。非常有效。