通过 SSLHandshakeException 收到致命警报:handshake_failure [英] Received fatal alert: handshake_failure through SSLHandshakeException

查看:41
本文介绍了通过 SSLHandshakeException 收到致命警报:handshake_failure的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了授权 SSL 连接的问题.我创建了 Struts Action,它使用客户端授权的 SSL 证书连接到外部服务器.在我的操作中,我试图将一些数据发送到银行服务器,但没有任何运气,因为服务器出现以下错误:

I have a problem with authorized SSL connection. I have created Struts Action that connects to external server with Client Authorized SSL certificate. In my Action I am trying to send some data to bank server but without any luck, because I have as a result from server the following error:

error: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

来自我的 Action 类的将数据发送到服务器的方法

My Method from my Action class that sends data to server

//Getting external IP from host
    URL whatismyip = new URL("http://automation.whatismyip.com/n09230945.asp");
    BufferedReader inIP = new BufferedReader(new InputStreamReader(whatismyip.openStream()));

    String IPStr = inIP.readLine(); //IP as a String

    Merchant merchant;

    System.out.println("amount: " + amount + ", currency: " + currency + ", clientIp: " + IPStr + ", description: " + description);

    try {

        merchant = new Merchant(context.getRealPath("/") + "merchant.properties");

    } catch (ConfigurationException e) {

        Logger.getLogger(HomeAction.class.getName()).log(Level.INFO, "message", e);
        System.err.println("error: " + e.getMessage());
        return ERROR;
    }

    String result = merchant.sendTransData(amount, currency, IPStr, description);

    System.out.println("result: " + result);

    return SUCCESS;

我的 Merchant.properties 文件:

My merchant.properties file:

bank.server.url=https://-servernameandport-/
https.cipher=-cipher-

keystore.file=-key-.jks
keystore.type=JKS
keystore.password=-password-
ecomm.server.version=2.0

encoding.source=UTF-8
encoding.native=UTF-8

我第一次觉得这是证书问题,我把它从.pfx 转换成.jks,但我也有同样的错误,没有任何变化.

For the first time I thought this is a certificate problem, I converted it from .pfx to .jks, but I have the same error, with no changes.

推荐答案

握手失败可能是由于多种原因:

The handshake failure could have occurred due to various reasons:

  • 客户端和服务器使用的密码套件不兼容.这将要求客户端使用(或启用)服务器支持的密码套件.
  • 使用的 SSL 版本不兼容(服务器可能只接受 TLS v1,而客户端只能使用 SSL v3).同样,客户端可能必须确保它使用兼容版本的 SSL/TLS 协议.
  • 服务器证书的信任路径不完整;客户端可能不信任服务器的证书.这通常会导致更详细的错误,但很有可能.通常解决方法是将服务器的 CA 证书导入客户端的信任库.
  • 证书是针对不同的域颁发的.同样,这会导致更详细的消息,但我会在此处说明修复方法,以防这是原因.在这种情况下,解决方案是让服务器(它似乎不是您的)使用正确的证书.

由于无法确定底层故障,最好打开-Djavax.net.debug=all 标志以启用已建立的 SSL 连接的调试.打开调试后,您可以查明握手中的哪些活动失败了.

Since, the underlying failure cannot be pinpointed, it is better to switch on the -Djavax.net.debug=all flag to enable debugging of the SSL connection established. With the debug switched on, you can pinpoint what activity in the handshake has failed.

更新

根据现有的详细信息,问题似乎是由于颁发给服务器的证书与根 CA 之间的证书信任路径不完整.大多数情况下,这是因为信任库中没有根CA的证书,导致证书信任路径不存在的情况;该证书基本上不受客户端信任.浏览器可以显示警告,以便用户可以忽略这一点,但 SSL 客户端的情况并非如此(例如 HttpsURLConnection 类,或任何 HTTP 客户端库,如 Apache HttpComponents 客户端).

Based on the details now available, it appears that the problem is due to an incomplete certificate trust path between the certificate issued to the server, and a root CA. In most cases, this is because the root CA's certificate is absent in the trust store, leading to the situation where a certificate trust path cannot exist; the certificate is essentially untrusted by the client. Browsers can present a warning so that users may ignore this, but the same is not the case for SSL clients (like the HttpsURLConnection class, or any HTTP Client library like Apache HttpComponents Client).

大多数这些客户端类/库将依赖于 JVM 用于证书验证的信任存储.在大多数情况下,这将是 JRE_HOME/lib/security 目录中的 cacerts 文件.如果使用 JVM 系统属性 javax.net.ssl.trustStore 指定了信任存储的位置,则该路径中的存储通常是客户端库使用的存储.如果您有疑问,请查看您的 Merchant 类,并找出它用于建立连接的类/库.

Most these client classes/libraries would rely on the trust store used by the JVM for certificate validation. In most cases, this will be the cacerts file in the JRE_HOME/lib/security directory. If the location of the trust store has been specified using the JVM system property javax.net.ssl.trustStore, then the store in that path is usually the one used by the client library. If you are in doubt, take a look at your Merchant class, and figure out the class/library it is using to make the connection.

将服务器的证书颁发机构 CA 添加到此信任存储区应该可以解决该问题.为此,您可以参考我的有关获取工具的相关问题的答案,但是Java keytool 实用程序 足以满足此目的.

Adding the server's certificate issuing CA to this trust store ought to resolve the problem. You can refer to my answer on a related question on getting tools for this purpose, but the Java keytool utility is sufficient for this purpose.

警告:信任库本质上是您信任的所有 CA 的列表.如果您放入不属于您不信任的 CA 的证书,那么在私钥可用的情况下,可以解密与具有该实体颁发的证书的站点的 SSL/TLS 连接.

Warning: The trust store is essentially the list of all CAs that you trust. If you put in an certificate that does not belong to a CA that you do not trust, then SSL/TLS connections to sites having certificates issued by that entity can be decrypted if the private key is available.

更新 #2:了解 JSSE 跟踪的输出

JVM 使用的密钥库和信任库通常在最开始列出,有点像下面这样:

The keystore and the truststores used by the JVM are usually listed at the very beginning, somewhat like the following:

keyStore is : 
keyStore type is : jks
keyStore provider is : 
init keystore
init keymanager of type SunX509
trustStore is: C:Javajdk1.6.0_21jrelibsecuritycacerts
trustStore type is : jks
trustStore provider is : 

如果使用了错误的信任库,那么您需要将服务器的证书重新导入正确的证书,或者重新配置服务器以使用列出的证书(如果您有多个JVM,则不推荐使用,并且所有这些都是用于不同的需求).

If the wrong truststore is used, then you'll need to re-import the server's certificate to the right one, or reconfigure the server to use the one listed (not recommended if you have multiple JVMs, and all of them are used for different needs).

如果您想验证信任证书列表是否包含所需的证书,则有一个相同的部分,开头为:

If you want to verify if the list of trust certs contains the required certs, then there is a section for the same, that starts as:

adding as trusted cert:
  Subject: CN=blah, O=blah, C=blah
  Issuer:  CN=biggerblah, O=biggerblah, C=biggerblah
  Algorithm: RSA; Serial number: yadda
  Valid from SomeDate until SomeDate

您需要查看服务器的 CA 是否是主题.

You'll need to look for if the server's CA is a subject.

握手过程会有几个显着的条目(你需要知道SSL才能详细了解它们,但为了调试当前问题,知道ServerHello中通常报告handshake_failure就足够了.

The handshake process will have a few salient entries (you'll need to know SSL to understand them in detail, but for the purpose of debugging the current problem, it will suffice to know that a handshake_failure is usually reported in the ServerHello.

1.ClientHello

连接初始化时会报一系列的条目.客户端在 SSL/TLS 连接设置中发送的第一条消息是 ClientHello 消息,通常在日志中报告为:

A series of entries will be reported when the connection is being initialized. The first message sent by the client in a SSL/TLS connection setup is the ClientHello message, usually reported in the logs as:

*** ClientHello, TLSv1
RandomCookie:  GMT: 1291302508 bytes = { some byte array }
Session ID:  {}
Cipher Suites: [SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA]
Compression Methods:  { 0 }
***

注意使用的密码套件.这可能必须与您的 Merchant.properties 文件中的条目一致,因为银行的图书馆可能会采用相同的约定.如果使用的约定不同,则无需担心,因为如果密码套件不兼容,ServerHello 会说明.

Note the cipher suites used. This might have to agree with the entry in your merchant.properties file, for the same convention might be employed by the bank's library. If the convention used is different, there is no cause of worry, for the ServerHello will state so, if the cipher suite is incompatible.

2.服务器你好

服务器以 ServerHello 响应,这将指示连接设置是否可以继续.日志中的条目通常是以下类型:

The server responds with a ServerHello, that will indicate if the connection setup can proceed. Entries in the logs are usually of the following type:

*** ServerHello, TLSv1
RandomCookie:  GMT: 1291302499 bytes = { some byte array}
Cipher Suite: SSL_RSA_WITH_RC4_128_SHA
Compression Method: 0
***

注意它选择的密码套件;这是服务器和客户端都可用的最佳套件.如果出现错误,通常不会指定密码套件.服务器的证书(以及可选的整个链)由服务器发送,可以在条目中找到:

Note the cipher suite that it has chosen; this is best suite available to both the server and the client. Usually the cipher suite is not specified if there is an error. The certificate of the server (and optionally the entire chain) is sent by the server, and would be found in the entries as:

*** Certificate chain
chain [0] = [
[
  Version: V3
  Subject: CN=server, O=server's org, L=server's location, ST =Server's state, C=Server's country
  Signature Algorithm: SHA1withRSA, OID = some identifer

.... the rest of the certificate
***

如果证书验证成功,您会看到类似如下的条目:

If the verification of the certificate has succeeded, you'll find an entry similar to:

Found trusted certificate:
[
[
  Version: V1
  Subject: OU=Server's CA, O="Server's CA's company name", C=CA's country
  Signature Algorithm: SHA1withRSA, OID = some identifier

上述步骤之一不会成功,导致握手失败,因为握手通常在此阶段完成(不是真的,但握手的后续阶段通常不会导致握手失败).您需要找出哪个步骤失败了,并发布相应的消息作为问题的更新(除非您已经理解了该消息,并且知道如何解决它).

One of the above steps would not have succeeded, resulting in the handshake_failure, for the handshake is typically complete at this stage (not really, but the subsequent stages of the handshake typically do not cause a handshake failure). You'll need to figure out which step has failed, and post the appropriate message as an update to the question (unless you've already understood the message, and you know what to do to resolve it).

这篇关于通过 SSLHandshakeException 收到致命警报:handshake_failure的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆