收到致命警报:handshake_failure通过SSLHandshakeException

时间:2011-06-15 06:23:25

标签: java ssl ssl-certificate sslhandshakeexception

我遇到授权SSL连接的问题。我创建了Struts Action,它通过Client Authorized SSL证书连接到外部服务器。在我的行动中,我试图将一些数据发送到银行服务器,但没有任何运气,因为我从服务器得到以下错误:

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

我的Action类从我的Action类发送数据到服务器

//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文件:

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,但我有相同的错误,没有任何更改。

19 个答案:

答案 0 :(得分:218)

答案 1 :(得分:19)

安装Java密码术扩展(JCE)无限强度(for JDK7 | for JDK8)可能会修复此错误。解压缩文件并按照自述文件进行安装。

答案 2 :(得分:15)

当客户端需要提供证书时,也会发生这种情况。服务器列出证书链后,可能会发生以下情况:

第3。证书申请 服务器将从客户端发出证书请求。该请求将列出服务器接受的所有证书。

*** CertificateRequest
Cert Types: RSA
Cert Authorities:
<CN=blah, OU=blah, O=blah, L=blah, ST=blah, C=blah>
<CN=yadda, DC=yadda, DC=yadda>
<CN=moreblah, OU=moreblah, O=moreblah, C=moreblah>
<CN=moreyada, OU=moreyada, O=moreyada, C=moreyada>
... the rest of the request
*** ServerHelloDone

<强> 4。客户证书链 这是客户端发送到服务器的证书。

*** Certificate chain
chain [0] = [
[
  Version: V3
  Subject: EMAILADDRESS=client's email, CN=client, OU=client's ou, O=client's Org, L=client's location, ST=client's state, C=client's Country
  Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5
  ... the rest of the certificate
*** ClientKeyExchange, RSA PreMasterSecret, TLSv1    
... key exchange info 

如果链中没有证书且服务器需要证书,那么您将在此处获得握手错误。可能的原因是找不到证书的路径。

<强> 5。证书验证 客户端要求服务器验证证书

*** CertificateVerify
... payload of verify check

只有在您发送证书时才会执行此步骤。

<强> 6。完成 服务器将以验证响应进行响应

*** Finished
verify_data:  { 345, ... }

答案 3 :(得分:15)

我不认为这可以解决第一个提问者的问题,但是对于谷歌来这里寻求答案:

在更新51上,默认情况下java 1.8禁止[1] RC4密码,我们可以在发行说明页面上看到:

  

错误修复:禁止RC4密码套件

     

RC4现在被视为受损密码。

     

已从Oracle JSSE实施中的客户端和服务器默认启用的密码套件列表中删除了RC4密码套件。这些密码套件仍然可以通过SSLEngine.setEnabledCipherSuites()SSLSocket.setEnabledCipherSuites()方法启用。请参阅JDK-8077109(非公开)。

如果您的服务器对此密码具有强烈的偏好(或仅使用此密码),则可以在java上触发handshake_failure

您可以测试连接到启用RC4密码的服务器(首先,尝试不使用enabled参数来查看是否触发handshake_failure,然后设置enabled

import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.*;

import java.util.Arrays;

/** Establish a SSL connection to a host and port, writes a byte and
 * prints the response. See
 * http://confluence.atlassian.com/display/JIRA/Connecting+to+SSL+services
 */
public class SSLRC4Poke {
    public static void main(String[] args) {
        String[] cyphers;
        if (args.length < 2) {
            System.out.println("Usage: "+SSLRC4Poke.class.getName()+" <host> <port> enable");
            System.exit(1);
        }
        try {
            SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
            SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket(args[0], Integer.parseInt(args[1]));

            cyphers = sslsocketfactory.getSupportedCipherSuites();
            if (args.length ==3){
                sslsocket.setEnabledCipherSuites(new String[]{
                    "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5",
                    "SSL_DH_anon_WITH_RC4_128_MD5",
                    "SSL_RSA_EXPORT_WITH_RC4_40_MD5",
                    "SSL_RSA_WITH_RC4_128_MD5",
                    "SSL_RSA_WITH_RC4_128_SHA",
                    "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
                    "TLS_ECDHE_RSA_WITH_RC4_128_SHA",
                    "TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
                    "TLS_ECDH_RSA_WITH_RC4_128_SHA",
                    "TLS_ECDH_anon_WITH_RC4_128_SHA",
                    "TLS_KRB5_EXPORT_WITH_RC4_40_MD5",
                    "TLS_KRB5_EXPORT_WITH_RC4_40_SHA",
                    "TLS_KRB5_WITH_RC4_128_MD5",
                    "TLS_KRB5_WITH_RC4_128_SHA"
                });     
            }

            InputStream in = sslsocket.getInputStream();
            OutputStream out = sslsocket.getOutputStream();

            // Write a test byte to get a reaction :)
            out.write(1);

            while (in.available() > 0) {
                System.out.print(in.read());
            }
            System.out.println("Successfully connected");

        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }
}

1 - https://www.java.com/en/download/faq/release_changes.xml

答案 4 :(得分:11)

握手失败可能是一个错误的TLSv1协议实现。

在我们的案例中,这有助于java 7:

File dest = new File(Environment.getExternalStorageDirectory() + "/NewFolder");
dest.mkdirs();

jvm将按此顺序进行协商。具有最新更新的服务器将执行1.2,有缺陷的服务器将下载到v1,并且与java 7中的类似v1一起使用。

答案 5 :(得分:8)

我尝试使用JDK 1.7时遇到此错误。 当我将JDK升级到jdk1.8.0_66时,一切正常。

因此,针对此问题的最简单的解决方案可能是 - 升级您的JDK ,它可以开始运作良好。

答案 6 :(得分:3)

假设您正在使用正确的SSL / TLS协议,正确配置了keyStoretrustStore,并确认证书本身不存在任何问题,您可能需要{ {3}}

strengthen your security algorithms中所述,您收到此错误的一个可能原因是由于使用了不兼容的密码套件。通过使用Vineet's answer中提供的local_policy文件夹更新我的JDK US_export_policy文件夹中的securitytextfield个jar,我就能够成功完成握手。

答案 7 :(得分:3)

就我而言,证书已导入,错误仍然存​​在,可以通过在连接之前添加using(SqlDataReader reader = _oCmd.ExecuteReader()) { DataTable dataTable = new DataTable(); dataTable.Load(reader); objLMT = ConvertTo<LMTUsage>(dataTable); } 来解决此问题

答案 8 :(得分:2)

我今天遇到了与OkHttp客户端相同的问题来获取基于https的网址。由于Https协议版本和服务器端与客户端之间的密码方法不匹配而导致

1)检查您的网站https协议版本和Cipher方法。

openssl>s_client -connect your_website.com:443 -showcerts

您将获得许多详细信息,关键信息如下所示:

SSL-Session:
    Protocol  : TLSv1
    Cipher    : RC4-SHA
2)配置您的http客户端,例如,在OkHttp client情况下:
@Test()
public void testHttpsByOkHttp() {
    ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
            .tlsVersions(TlsVersion.TLS_1_0) //protocol version
            .cipherSuites(
                    CipherSuite.TLS_RSA_WITH_RC4_128_SHA, //cipher method
                    CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
                    CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
                    CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256)
            .build();

    OkHttpClient client = new OkHttpClient();
    client.setConnectionSpecs(Collections.singletonList(spec));
    Request request = new Request.Builder().url("https://your_website.com/").build();
    try {
        Response response = client.newCall(request).execute();
        if(response.isSuccessful()){
            logger.debug("result= {}", response.body().string());
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

这将得到我们想要的。

答案 9 :(得分:2)

如果我的Java客户端进程配置了

,我发现HTTPS服务器以这种方式失败
-Djsse.enableSNIExtension=false

handshake_failure成功完成后但数据流开始之前,ServerHello连接失败。

没有明确的错误消息确定问题,错误看起来像

main, READ: TLSv1.2 Alert, length = 2
main, RECV TLSv1.2 ALERT:  fatal, handshake_failure
%% Invalidated:  [Session-3, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384]
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

我尝试使用和不使用“-Djsse.enableSNIExtension=false”选项

来隔离此问题

答案 10 :(得分:1)

我是TLS版本不兼容的错误。

以前是TLSv1我更改了它TLSV1.2这解决了我的问题。

答案 11 :(得分:1)

我正在使用com.google.api http客户端。当我与内部公司站点进行通信时,当我错误地使用https而不是http时,我遇到了这个问题。

{{1}}

答案 12 :(得分:1)

我有类似的问题;升级到Apache HTTPClient 4.5.3修复它。

答案 13 :(得分:1)

哎呀!对我来说,这简直就是Java版本的问题。我在使用JRE 1.6时遇到握手错误,并且在使用JRE 1.8.0_144时一切正常。

答案 14 :(得分:0)

免责声明:我不知道答案是否会对很多人有所帮助,只是因为它可能会分享。

使用Parasoft SOATest发送请求XML(SOAP)时出现此错误。

问题是,在添加证书并对其进行身份验证后,我从下拉列表中选择了错误的别名

答案 15 :(得分:0)

就我而言,该网站只能使用TLSv1.2。我使用的是Apache httpclient 4.5.6,我使用以下代码并安装jce来解决此问题(JDK1.7):

jce

jdk7 http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html

jdk 8 http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html

代码:

SSLContext sslContext = SSLContext.getDefault();

  SSLConnectionSocketFactory sslConnectionFactory = new SSLConnectionSocketFactory(
      sslContext,
      new String[]{"TLSv1.2"}, // important
      null,
      NoopHostnameVerifier.INSTANCE);

  Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
      .register("https", sslConnectionFactory)
      .register("http", PlainConnectionSocketFactory.INSTANCE)
      .build();

  HttpClientConnectionManager ccm = new BasicHttpClientConnectionManager(registry);
  httpclient = HttpClientBuilder.create().
      .setSSLSocketFactory(sslConnectionFactory)
      .setConnectionManager(ccm)
      .build();

答案 16 :(得分:0)

要从开发人员(项目1)和系统管理员(项目2和3)的角度进行故障排除:

  1. 通过> as.tibble(cbind(df, binconf(df$count, df$n))) # A tibble: 6 x 6 id count n PointEst Lower Upper <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> 1 1 4 22 0.182 0.0731 0.385 2 2 1 65 0.0154 0.000789 0.0821 3 3 22 34 0.647 0.479 0.785 4 4 4545 6323 0.719 0.708 0.730 5 5 33 35 0.943 0.814 0.984 6 6 23 45 0.511 0.370 0.650 在Java上启用SSL握手调试。
  2. 如果在执行以下步骤时在密码中观察到-Djavax.net.debug=ssl:handshake:verbose,则通过sudo apt install ssldump在服务器上安装ssldump或通过遵循此link从源代码进行编译。
  3. 在服务器上,Unknown value
  4. 检查有关失败的真实reason的日志。

ssldump日志无法正常握手的示例:

sudo ssldump -k <your-private-key> -i <your-network-interface>

ssldump日志成功握手的示例

New TCP connection #1: 10.1.68.86(45308) <-> 10.1.68.83(5671)
1 1  0.0111 (0.0111)  C>S  Handshake
      ClientHello
        Version 3.3
        cipher suites
        TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
        TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
        TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
        TLS_RSA_WITH_AES_256_GCM_SHA384
        TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
        TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
        TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
        TLS_DHE_DSS_WITH_AES_256_GCM_SHA384
        TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
        TLS_RSA_WITH_AES_128_GCM_SHA256
        TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
        TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
        TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
        TLS_DHE_DSS_WITH_AES_128_GCM_SHA256
        TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
        TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
        TLS_RSA_WITH_AES_256_CBC_SHA256
        TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
        TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
        TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
        TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
        TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
        TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
        TLS_RSA_WITH_AES_256_CBC_SHA
        TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
        TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
        TLS_DHE_RSA_WITH_AES_256_CBC_SHA
        TLS_DHE_DSS_WITH_AES_256_CBC_SHA
        TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
        TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
        TLS_RSA_WITH_AES_128_CBC_SHA256
        TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
        TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
        TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
        TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
        TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
        TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
        TLS_RSA_WITH_AES_128_CBC_SHA
        TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
        TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
        TLS_DHE_RSA_WITH_AES_128_CBC_SHA
        TLS_DHE_DSS_WITH_AES_128_CBC_SHA
        TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        compression methods
                  NULL
1 2  0.0122 (0.0011)  S>C  Alert
    level           fatal
    value           insufficient_security
1    0.0126 (0.0004)  S>C  TCP RST

无法正常运行Java日志的示例

New TCP connection #1: 10.1.68.86(56558) <-> 10.1.68.83(8443)
1 1  0.0009 (0.0009)  C>S  Handshake
      ClientHello
        Version 3.3
        cipher suites
        TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
        TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
        TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
        Unknown value 0xcca9
        Unknown value 0xcca8
        Unknown value 0xccaa
        TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
        TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
        TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
        TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
        TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
        TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
        TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
        TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
        TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
        TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
        TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
        TLS_DHE_RSA_WITH_AES_256_CBC_SHA
        TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
        TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
        TLS_DHE_RSA_WITH_AES_128_CBC_SHA
        TLS_RSA_WITH_AES_256_GCM_SHA384
        TLS_RSA_WITH_AES_128_GCM_SHA256
        TLS_RSA_WITH_AES_256_CBC_SHA256
        TLS_RSA_WITH_AES_128_CBC_SHA256
        TLS_RSA_WITH_AES_256_CBC_SHA
        TLS_RSA_WITH_AES_128_CBC_SHA
        TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        compression methods
                  NULL
1 2  0.0115 (0.0106)  S>C  Handshake
      ServerHello
        Version 3.3
        session_id[0]=

        cipherSuite         TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
        compressionMethod                   NULL
1 3  0.0115 (0.0000)  S>C  Handshake
      Certificate
1 4  0.0115 (0.0000)  S>C  Handshake
      ServerKeyExchange
Not enough data. Found 294 bytes (expecting 32767)
1 5    0.0115   (0.0000)    S>C    Handshake
        ServerHelloDone
1 6    0.0141   (0.0025)    C>S    Handshake
        ClientKeyExchange
Not enough data. Found 31 bytes (expecting 16384)
1 7    0.0141   (0.0000)    C>S    ChangeCipherSpec
1 8    0.0141   (0.0000)    C>S      Handshake
1 9    0.0149   (0.0008)    S>C    Handshake
1 10   0.0149   (0.0000)    S>C    ChangeCipherSpec
1 11   0.0149   (0.0000)    S>C      Handshake

答案 17 :(得分:0)

就我而言,我的1.1版存在一个问题。我很容易用curl重现问题。该服务器不支持低于TLS1.2的版本。

这收到了握手问题:

curl --insecure --tlsv1.1 -i https://youhost --noproxy "*"

在1.2版中,它运行良好:

curl --insecure --tlsv1.2 -i https://youhost --noproxy "*"

服务器正在运行Weblogic,并且在setEnvDomain.sh中添加此参数使其可以与TLSv1.1一起使用:

-Dweblogic.security.SSL.minimumProtocolVersion=TLSv1.1

答案 18 :(得分:0)

由于Java版本而发生此问题。我正在使用1.8.0.231 JDK并收到此错误。我已经将Java版本从1.8.0.231降级到1.8.0.171,现在可以正常使用了。