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

Posted

技术标签:

【中文标题】ChangeCipherSpec - javax.net.ssl.SSLHandshakeException:收到致命警报:handshake_failure【英文标题】:ChangeCipherSpec - javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure 【发布时间】:2017-01-20 05:29:51 【问题描述】:

当我收到该错误时,我正在尝试使用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

【问题讨论】:

请提供更多关于您的问题的信息,需要上述异常的代码来调试发生了什么。 @SpiXel 添加了代码。 【参考方案1】:

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

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

【讨论】:

我已经添加了整个 ssl 调试跟踪。 @deveshrastogi:正如预期的那样:可以看到来自服务器的 CertificateRequest,但客户端没有发送请求的证书。 @deveshrastogi:如果您没有客户端证书,请获取一份。如果您有一个How to use SSL with a self-signed certificate in groovy? 可能会有所帮助。这是我使用搜索引擎几秒钟后发现的,我个人对 groovy 没有经验。

以上是关于ChangeCipherSpec - javax.net.ssl.SSLHandshakeException:收到致命警报:handshake_failure的主要内容,如果未能解决你的问题,请参考以下文章

Java EE 6 @javax.annotation.ManagedBean 与 @javax.inject.Named 与 @javax.faces.ManagedBean

javax.inject.Singleton 和 javax.ejb.Singleton 的区别

包 javax.mail 和 javax.mail.internet 不存在

javax.servlet.ServletException:java.lang.NoClassDefFoundError:javax/servlet/jsp/jstl/core/Conditiona

javax.servlet.ServletContext 和 javax.servlet.ServletException 类型无法解析

com.android.volley.NoConnectionError:javax.net.ssl.SSLHandshakeException:javax.net.ssl.SSLProtocolEx