我试图用基本的auth消耗一个宁静的ws.我没有将任何证书导入我的密钥库.当我使用chrome插件Advance Rest client
测试它时(使用base64编码的基本身份验证用户名:pass).我可以看到回复.到现在为止还挺好.但是当我开发Java代码来使用这个ws时,我得到了SSL的失败:
org.springframework.web.client.ResourceAccessException: I/O error: Received fatal alert: handshake_failure; nested exception is javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:453) at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:401) at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:377) at test.Rest.main(Rest.java:37) Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure at sun.security.ssl.Alerts.getSSLException(Unknown Source) at sun.security.ssl.Alerts.getSSLException(Unknown Source)
我的问题是:如果问题是因为我没有将证书导入我的密钥库,那么Java代码和插件都不应该一起工作.在这里,插件可以工作,但我的代码没有.是什么原因?我的代码有些不对劲?
贝娄是我的代码
RestTemplate restTemplate = new RestTemplate(); String plainCreds = "username:pass"; byte[] plainCredsBytes = plainCreds.getBytes(Charset.forName("US-ASCII") ); byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes); String base64Creds = new String(base64CredsBytes); HttpHeaders headers = new HttpHeaders(); headers.add("Authorization", "Basic " + base64Creds); ResponseEntityresponse = restTemplate.exchange("https://url",HttpMethod.GET,new HttpEntity(headers),String.class);
这是日志文件的链接:(我已经用XXXXXX替换了我的服务器名称) http://www.filedropper.com/ssllog
运行后:openssl s_client -showcerts -tls1 -connect host:port
WARNING: can't open config file: /usr/local/ssl/openssl.cnf CONNECTED(00000164) 8088:error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version number:.\ssl\s3_pkt.c:362: --- no peer certificate available --- No client certificate CA names sent --- SSL handshake has read 5 bytes and written 0 bytes --- New, (NONE), Cipher is (NONE) Secure Renegotiation IS NOT supported Compression: NONE Expansion: NONE No ALPN negotiated SSL-Session: Protocol : TLSv1 Cipher : 0000 Session-ID: Session-ID-ctx: Master-Key: Key-Arg : None PSK identity: None PSK identity hint: None SRP username: None Start Time: 1452011344 Timeout : 7200 (sec) Verify return code: 0 (ok) ---
这是我运行命令openssl s_client -connect server:port时的输出
WARNING: can't open config file: /usr/local/ssl/openssl.cnf CONNECTED(00000164) depth=0 C = US, ST = "XXXXXX", L = XXXXXX, O = XXXXXX, OU = xxxxx, CN = XXXXXXXXX.test.intranet, emailAddress = xxxxx@xxxxx verify error:num=20:unable to get local issuer certificate verify return:1 depth=0 C = US, ST = "XXXXXXX ", L = XXXXX, O = XXXXXX, OU = xxxxxx, CN = XXXXXXXXX.test.intranet, emailAddress = xxxxx@xxxxx verify error:num=21:unable to verify the first certificate verify return:1 --- Certificate chain 0 s:/C=US/ST=XXXXXXX /L=XXXXX/O=XXXXXX/OU=XXXXX/CN=XXXXXX.test.intranet/emailAddress=xxxxx@xxxxx i:/DC=intranet/DC=xxxx/CN=XXXXXX DEV Issuing CA --- Server certificate -----BEGIN CERTIFICATE----- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXX..... -----END CERTIFICATE----- subject=/C=US/ST=XXXXXXX /L=XXXXX/O=XXXXXX/OU=XXXXX/CN=XXXXXX.test.intranet/emailAddress=xxxxx@xxxxx issuer=/DC=intranet/DC=XXX/CN=XXXXX DEV Issuing CA --- No client certificate CA names sent Peer signing digest: SHA512 Server Temp Key: XXXXX, P-256, 256 bits --- SSL handshake has read 1895 bytes and written 443 bytes --- New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-GCM-SHA256 Server public key is 2048 bit Secure Renegotiation IS supported Compression: NONE Expansion: NONE No ALPN negotiated SSL-Session: Protocol : TLSv1.2 Cipher : ECDHE-RSA-AES128-GCM-SHA256 Session-ID: 568BF22A5CDBF103155264BBC056B272168AE0777CBC10F055705EB2DD907E5A Session-ID-ctx: Master-Key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Key-Arg : None PSK identity: None PSK identity hint: None SRP username: None Start Time: 1452012074 Timeout : 300 (sec) Verify return code: 21 (unable to verify the first certificate) --- read:errno=0
Michal Foksa.. 8
从javax.net.debug
日志中我可以看到您正在使用Java 7并且客户端解析为TLSv1.从openssl
您的服务器不支持TLSv1的输出.
TLS版本 默认情况下,Java 7中禁用了1.1和1.2.
虽然Java SE 7发行版中的SunJSSE支持TLS 1.1和TLS 1.2,但默认情况下不会为客户端连接启用任何版本.某些服务器无法正确实现前向兼容性,并拒绝与TLS 1.1或TLS 1.2客户端通信.对于互操作性,SunJSSE默认情况下不为客户端连接启用TLS 1.1或TLS 1.2.
通过以下方式启用TLSv1.1和TLSv1.2:
JVM参数:
-Dhttps.protocols=TLSv1.2,TLSv1.1,TLSv1
或者从Java代码设置相同的属性:
System.setProperty("https.protocols", "TLSv1.2,TLSv1.1,TLSv1");
或者为Java 7安装JCE Unlimited Strength策略文件.我不是100%确定这一步是否能解决问题虽然总是值得安装JCE,同时它允许JVM使用更强版本的现有算法.
2016年9月29日更新:
在选项1和2中,协议的顺序从更好到更差(TLS版本1.2到1).
从javax.net.debug
日志中我可以看到您正在使用Java 7并且客户端解析为TLSv1.从openssl
您的服务器不支持TLSv1的输出.
TLS版本 默认情况下,Java 7中禁用了1.1和1.2.
虽然Java SE 7发行版中的SunJSSE支持TLS 1.1和TLS 1.2,但默认情况下不会为客户端连接启用任何版本.某些服务器无法正确实现前向兼容性,并拒绝与TLS 1.1或TLS 1.2客户端通信.对于互操作性,SunJSSE默认情况下不为客户端连接启用TLS 1.1或TLS 1.2.
通过以下方式启用TLSv1.1和TLSv1.2:
JVM参数:
-Dhttps.protocols=TLSv1.2,TLSv1.1,TLSv1
或者从Java代码设置相同的属性:
System.setProperty("https.protocols", "TLSv1.2,TLSv1.1,TLSv1");
或者为Java 7安装JCE Unlimited Strength策略文件.我不是100%确定这一步是否能解决问题虽然总是值得安装JCE,同时它允许JVM使用更强版本的现有算法.
2016年9月29日更新:
在选项1和2中,协议的顺序从更好到更差(TLS版本1.2到1).