ChangeCipherSpec - javax.net.ssl.SSLHandshakeException:收到致命警报:handshake_failure

时间:2016-09-12 17:54:20

标签: java ssl sslhandshakeexception

当我收到错误时,我正尝试使用HttpsURLConnection通过SSL连接到托管SOAP服务的https URL。在SSL模式下进行调试时,我理解这一点 ClientHello, ServerHello, Certificate, ServerHelloDone, ClientKeyExchange成功举办。仅在ChangeCipherSpec阶段的服务器回复期间发生异常。

ssl调试跟踪如下:

*** ClientHello, TLSv1.2
RandomCookie:  
GMT: 1456906493 
bytes = {<some-byte-data>}
Session ID:  {}
Cipher Suites: [SSL_RSA_WITH_RC4_128_SHA]
Compression Methods:  { 0 }
Extension signature_algorithms, signature_algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA224withECDSA, SHA224withRSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA, MD5withRSA
Extension server_name, server_name: [host_name: www4.ipg-online.com]
Extension renegotiation_info, renegotiated_connection: <empty>
***
http-bio-8443-exec-5, WRITE: TLSv1.2 Handshake, length = 110
http-bio-8443-exec-5, READ: TLSv1.2 Handshake, length = 3951
*** ServerHello, TLSv1.2
RandomCookie:  
GMT: 1456906492 
bytes = {<some-byte-data>}
Session ID:  {198, 60, 71, 156, 166, 35, 121, 29, 184, 198, 218, 137, 212, 112, 9, 71, 249, 16, 69, 197, 109, 109, 113, 199, 214, 38, 187, 124, 229, 132, 43, 51}
Cipher Suite: SSL_RSA_WITH_RC4_128_SHA
Compression Method: 0
Extension renegotiation_info, renegotiated_connection: <empty>
***
** SSL_RSA_WITH_RC4_128_SHA
*** Certificate chain
chain [0] = <this is the hostname certificate which is also present in my keystore>
chain [1] = <blah blah>
chain [2] = <blah blah>
***
Found trusted certificate:
[0] <blah blah> //this is that hostname certificate
*** CertificateRequest
Cert Types: 
RSA
, 
DSS

Supported Signature Algorithms: MD5withRSA, SHA1withRSA, SHA256withRSA
Cert Authorities: <cert details of the hostname cert found in keystore>
*** ServerHelloDone
*** Certificate chain
***
*** ClientKeyExchange, RSA PreMasterSecret, TLSv1.2
http-bio-8443-exec-5, WRITE: TLSv1.2 Handshake, length = 289
SESSION KEYGEN:
PreMaster Secret: <some data>
CONNECTION KEYGEN:
Client Nonce: <some data>
Server Nonce: <some data>
Master Secret: <some data>
Client MAC write Secret: <some data>
Server MAC write Secret: <some data>
Client write key: <some data>
Server write key: <some data>
... no IV derived for this protocol
http-bio-8443-exec-5, WRITE: TLSv1.2 Change Cipher Spec, length = 21
*** Finished
verify_data:  {<some byte data>}
***
http-bio-8443-exec-5, WRITE: TLSv1.2 Handshake, length = 36
http-bio-8443-exec-5, READ: TLSv1.2 Alert, length = 22
http-bio-8443-exec-5
, RECV TLSv1.2 ALERT:  
fatal, 
handshake_failure
%% Invalidated:  [Session-2, SSL_RSA_WITH_RC4_128_SHA]
%% Invalidated:  [Session-3, SSL_RSA_WITH_RC4_128_SHA]
http-bio-8443-exec-5, called closeSocket()
http-bio-8443-exec-5, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert:   handshake_failure
http-bio-8443-exec-5, called close()
http-bio-8443-exec-5, called closeInternal(true)

我的环境设置

-Djavax.net.debug=ssl
-Djavax.net.ssl.keyStore=/Library/Java/JavaVirtualMachines/jdk1.7.0_71.jdk/Contents/Home/jre/lib/security/cacerts
-Djavax.net.ssl.keyStorePassword=<password>
-Dhttps.cipherSuites=SSL_RSA_WITH_RC4_128_SHA

代码

我正在使用groovy。

String path = "/Library/Java/JavaVirtualMachines/jdk1.7.0_71.jdk/Contents/Home/jre/lib/security/cacerts"
char[] trustStorePassword = <password>.toCharArray();

InputStream trustStream = new FileInputStream(path);
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(trustStream, trustStorePassword);
trustStream.close()

TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustFactory.init(trustStore);
TrustManager[] trustManagers = trustFactory.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, trustManagers, null);

URL url = new URL(<url-to-server>)
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
String userCredentials = "uname:passwd"
String basicAuth = "Basic " + new String(userCredentials.getBytes().encodeAsBase64())
con.setAllowUserInteraction(true)
con.setRequestProperty("Authorization", basicAuth);
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type", "text/xml");
con.setSSLSocketFactory(sslContext.getSocketFactory());
con.setDoOutput(true)

String urlParameters = "some-xml-data-as-string"
OutputStream wr = con.getOutputStream()
wr.write(urlParameters.getBytes("UTF-8"));
wr.flush();
wr.close();
int responseCode = con.getResponseCode(); //this is where i get exception

1 个答案:

答案 0 :(得分:1)

  

...仅在ChangeCipherSpec阶段发生异常。

输出中缺少先前的消息,因此只能猜测:因为服务器在握手的最后阶段发送警报,即在协商密码并且服务器已发送其证书之后,最可能的原因是服务器已从客户端请求了客户端未提供的证书或服务器不喜欢的证书。您可能会在服务器端的某些日志消息中找到更多详细信息。