Apache httpclient javax.net.ssl.SSLHandshakeException:

Posted

技术标签:

【中文标题】Apache httpclient javax.net.ssl.SSLHandshakeException:【英文标题】:Apache httpclient javax.net.ssl.SSLHandshakeException: 【发布时间】:2014-04-10 16:14:22 【问题描述】:

我正在尝试连接到具有 SSLv3 安全性的服务。

提供以下文件后,curl和浏览器就可以通信了

1. ca.crt
2. private.key
2. client.crt

我使用所有 3 个文件创建了一个带有以下 cmd 的 ssl 密钥库

openssl  pkcs12 -export  -in client.crt  -inkey private.key  -CAfile ca.crt  -out sslstore.p12

然后使用keytool将其导入为java truststore

keytool -importkeystore -srckeystore sslstore.p12  -srcstoretype PKCS12  -destkeystore truststore.jks

之后,我点击了以下链接https://hc.apache.org/httpcomponents-client-ga/httpclient/examples/org/apache/http/examples/client/ClientCustomSSL.java 连接到网址。仅将协议从 TLSv1 更改为 SSLv3。

我总是在连接时得到 javax.net.ssl.SSLHandshakeException: excdption。

如前所述,这些键适用于 curl / 浏览器。

EDIT-2 更改 SSLContexts.custom() 附近的代码

来自:

sslcontext = SSLContexts.custom()                        
                    .loadTrustMaterial(keyStore, new TrustSelfSignedStrategy())
                    .build();

到:

sslcontext = SSLContexts.custom()
                    .loadKeyMaterial(keyStore, "changeit".toCharArray())
                    .loadTrustMaterial(keyStore, new TrustSelfSignedStrategy())
                    .build();

工作。请注意,我使用的是相同的密钥库。

EDIT-1 代码:

public static void main (String[] args) throws KeyStoreException, FileNotFoundException 


        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());

        InputStream is  = Thread.currentThread().getContextClassLoader().getResourceAsStream("certs/ppro.jks");

        try 
            keyStore.load(is,"changeit".toCharArray());
         catch (IOException | NoSuchAlgorithmException | CertificateException e) 
            e.printStackTrace();
        
        // Trust own CA and all self-signed certs
        SSLContext sslcontext = null;
        try 
            sslcontext = SSLContexts.custom()
                    .loadTrustMaterial(keyStore, new TrustSelfSignedStrategy())
                    .build();
         catch (NoSuchAlgorithmException | KeyManagementException e) 
            e.printStackTrace();
        
        try 
            sslcontext.loadKeyMaterial(keyStore,"changeit".toCharArray());
         catch (NoSuchAlgorithmException | KeyManagementException e) 
            e.printStackTrace();
        
        // Allow TLSv1 protocol only
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                sslcontext,
                new String[]  "SSLv3"  ,
                null,
                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);

        try (CloseableHttpClient httpclient = HttpClients.custom()
                .setSSLSocketFactory(sslsf)
                .build()) 
            HttpPost httpPost = new HttpPost(URL);
            try 

                CloseableHttpResponse response = httpclient.execute(httpPost);
                System.out.println(response);

             catch (IOException e) 
                e.printStackTrace();
            
         catch (IOException e) 
            e.printStackTrace();
        

    

EDIT-0

这是来自 java 的堆栈跟踪,包括一些 ssl 调试信息。

*** ClientKeyExchange, RSA PreMasterSecret, SSLv3
main, WRITE: SSLv3 Handshake, length = 132
SESSION KEYGEN:
PreMaster Secret:
0000: 03 00 E7 89 C2 9D AB 1A   3B 75 85 5B 4E C6 EE 10  ........;u.[N...
0010: 83 0F 3C 37 74 3C D0 6A   AF 51 D7 EC E2 B9 50 35  ..<7t<.j.Q....P5
0020: CC 8D 58 93 39 5D B6 4F   BE DB 5A F4 E3 0A BE 42  ..X.9].O..Z....B
CONNECTION KEYGEN:
Client Nonce:
0000: 53 47 9A BD 4B 14 BC AF   B0 2B FB 6C 49 9C E4 53  SG..K....+.lI..S
0010: 21 F3 53 C8 7F 74 1C 5C   C0 5E 6D 67 18 50 10 4D  !.S..t.\.^mg.P.M
Server Nonce:
0000: 53 47 9A BD B2 5C 44 89   92 BE 4B FF F4 F6 60 FE  SG...\D...K...`.
0010: D6 18 67 96 6A 13 3C 80   9F D2 56 29 1A 60 B4 E4  ..g.j.<...V).`..
Master Secret:
0000: E3 E5 11 9F 87 B6 A3 4E   8C 9C F1 20 E9 A5 50 62  .......N... ..Pb
0010: DD E8 E6 A3 61 FC C0 56   0C 1E A8 29 BC F4 5C 52  ....a..V...)..\R
0020: DE CE 98 64 0E 57 07 E6   22 24 08 1A 77 8A 97 48  ...d.W.."$..w..H
Client MAC write Secret:
0000: 44 98 8B 9C C4 59 C2 4E   21 66 67 6D 96 C4 FE 9C  D....Y.N!fgm....
0010: 2B 74 AD 61                                        +t.a
Server MAC write Secret:
0000: 29 7D 5A F2 71 B6 55 C0   CF BB 82 66 02 03 B1 35  ).Z.q.U....f...5
0010: 5A 69 83 99                                        Zi..
Client write key:
0000: B5 32 F7 7C DC DB 4F B4   00 48 66 A4 B3 C0 7D 6B  .2....O..Hf....k
Server write key:
0000: CB 80 F4 76 53 92 6F 87   3B A3 9D B2 A9 6F 40 85  ...vS.o.;....o@.
Client write IV:
0000: B7 89 4A FC 43 7A 1B 3C   DD 83 7F CE A1 FC FB BF  ..J.Cz.<........
Server write IV:
0000: 84 92 B7 B4 EB 13 B6 77   EF 87 B0 E1 04 41 5C 4D  .......w.....A\M
main, WRITE: SSLv3 Change Cipher Spec, length = 1
*** Finished
verify_data:   116, 66, 54, 146, 216, 200, 254, 221, 170, 236, 204, 2, 17, 139, 161, 37, 205, 117, 131, 95, 255, 123, 158, 100, 150, 110, 105, 209, 22, 205, 31, 196, 95, 84, 59, 252 
***
main, WRITE: SSLv3 Handshake, length = 64
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
    at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1959)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1077)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1339)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1323)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:275)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:254)
    at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:118)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:314)
    at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:363)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:219)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:195)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:85)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:186)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:106)
    at com.masterpayment.frontend.gateway.beconnector.GiroGateClient.main(GiroGateClient.java:66)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
main, READ: SSLv3 Alert, length = 2
main, RECV SSLv3 ALERT:  fatal, handshake_failure
%% Invalidated:  [Session-1, TLS_RSA_WITH_AES_128_CBC_SHA]
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

【问题讨论】:

【参考方案1】:

apache 示例只设置了一个信任库。那只会使用 CA 证书。您还需要设置一个“身份”来处理客户端证书。我知道您将它们全部放在同一个 java 密钥库中,这可能仍然可以(但通常它们位于单独的文件中)。

该示例调用 loadTrustMaterial()。您还需要调用 loadKeyMaterial()。

【讨论】:

你能提供一个例子或一个链接吗?如何创建身份? 您似乎已经创建了一个身份。您只是碰巧将它与 CA 证书放在同一个密钥库中。请在 SSLContexts.custom() 周围发布您的代码 我将 SSLContexts.custom() 周围的代码更改为 sslcontext = SSLContexts.custom() .loadKeyMaterial(keyStore, "changeit".toCharArray()) .loadTrustMaterial(keyStore, new TrustSelfSignedStrategy()) 。构建();【参考方案2】:

我的直觉是您遇到了 PKIX 链验证错误 - 请尝试以下操作:

openssl pkcs12 \
    -export \
    -chain \
    -in client.crt \
    -inkey private.key \
    -CAfile ca.crt \
    -out sslstore.p12

请注意以上内容 - 我添加了“-chain”选项 - 这应该使用适当的证书链接将证书正确导出到 PKCS#12 存档中。

在过去的 6 个月里,我遇到这种情况的次数超过了我的数,而且它总是让我着迷。

如果这不起作用,请同时添加一些来自 Java 的堆栈跟踪。

【讨论】:

我试过了。这次我得到了 javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: error。我已经将 ca.crt 导入 $JRE_HOME/lib/security/cacerts 在我将 ca.crt 导入信任库之前会发生这种情况。导入后,我得到了原始问题中提到的异常。 呃,我讨厌那个例外的含糊不清。我想尝试在本地证明这一点,你能告诉我你使用的是哪个版本 我使用的是 apche httpclient 的 4.3.3

以上是关于Apache httpclient javax.net.ssl.SSLHandshakeException:的主要内容,如果未能解决你的问题,请参考以下文章

commons-httpclient 和 httpclient 之间有啥关系,都来自 apache

新旧apache HttpClient 获取httpClient方法

Apache HttpClient

httpClient 保持session

HttpClient使用学习

Apache HttpClient API 中的 CloseableHttpClient 和 HttpClient 有啥区别?