How do I set SSL protocol version in java? And how

2020-05-19 10:01发布

I am using Apache HttpClient 4.3 to interact with the API of hubic.com. My minimal reproducable example is just a one liner:

HttpClientBuilder.create().build().execute(new HttpGet("https://hubic.com"));

However that throws:

Exception in thread "main" javax.net.ssl.SSLException: Received fatal alert: protocol_version
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:208)
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
    at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1991)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1104)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1343)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1371)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1355)
    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:117)
    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:86)
    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)

Here is the output if I run with System.setProperty("javax.net.debug", "all");:

trustStore is: /usr/lib/jvm/java-8-oracle/jre/lib/security/cacerts
trustStore type is : jks
trustStore provider is : 
init truststore

adding as trusted cert: [... extremely large list ...]

trigger seeding of SecureRandom
done seeding SecureRandom
Ignoring unavailable cipher suite: TLS_DHE_DSS_WITH_AES_256_GCM_SHA384
Ignoring unavailable cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
Ignoring unavailable cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA256
Ignoring unavailable cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_RSA_WITH_AES_256_GCM_SHA384
Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
Ignoring unavailable cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
Allow unsafe renegotiation: false
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 for SSLv3
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 for SSLv3
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_128_CBC_SHA256 for SSLv3
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 for SSLv3
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 for SSLv3
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 for SSLv3
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 for SSLv3
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_128_CBC_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 for TLSv1.1
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 for TLSv1.1
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_128_CBC_SHA256 for TLSv1.1
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 for TLSv1.1
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 for TLSv1.1
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 for TLSv1.1
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 for TLSv1.1
%% No cached client session
*** ClientHello, TLSv1.2
RandomCookie:  GMT: 1402182685 bytes = { 227, 155, 148, 161, 7, 104, 221, 182, 254, 133, 216, 198, 118, 211, 223, 229, 43, 82, 207, 1, 102, 245, 112, 117, 253, 69, 43, 162 }
Session ID:  {}
Cipher Suites: [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_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 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_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, SSL_RSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS_ECDH_RSA_WITH_RC4_128_SHA, SSL_RSA_WITH_RC4_128_MD5, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
Compression Methods:  { 0 }
Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1}
Extension ec_point_formats, formats: [uncompressed]
Extension signature_algorithms, signature_algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA224withECDSA, SHA224withRSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA, MD5withRSA
Extension server_name, server_name: [type=host_name (0), value=hubic.com]
***
[write] MD5 and SHA1 hashes:  len = 225
0000: 01 00 00 DD 03 03 54 94   9C 1D E3 9B 94 A1 07 68  ......T........h
0010: DD B6 FE 85 D8 C6 76 D3   DF E5 2B 52 CF 01 66 F5  ......v...+R..f.
0020: 70 75 FD 45 2B A2 00 00   46 C0 23 C0 27 00 3C C0  pu.E+...F.#.'.<.
0030: 25 C0 29 00 67 00 40 C0   09 C0 13 00 2F C0 04 C0  %.).g.@...../...
0040: 0E 00 33 00 32 C0 2B C0   2F 00 9C C0 2D C0 31 00  ..3.2.+./...-.1.
0050: 9E 00 A2 C0 08 C0 12 00   0A C0 03 C0 0D 00 16 00  ................
0060: 13 C0 07 C0 11 00 05 C0   02 C0 0C 00 04 00 FF 01  ................
0070: 00 00 6E 00 0A 00 34 00   32 00 17 00 01 00 03 00  ..n...4.2.......
0080: 13 00 15 00 06 00 07 00   09 00 0A 00 18 00 0B 00  ................
0090: 0C 00 19 00 0D 00 0E 00   0F 00 10 00 11 00 02 00  ................
00A0: 12 00 04 00 05 00 14 00   08 00 16 00 0B 00 02 01  ................
00B0: 00 00 0D 00 1A 00 18 06   03 06 01 05 03 05 01 04  ................
00C0: 03 04 01 03 03 03 01 02   03 02 01 02 02 01 01 00  ................
00D0: 00 00 0E 00 0C 00 00 09   68 75 62 69 63 2E 63 6F  ........hubic.co
00E0: 6D                                                 m
main, WRITE: TLSv1.2 Handshake, length = 225
[Raw write]: length = 230
0000: 16 03 03 00 E1 01 00 00   DD 03 03 54 94 9C 1D E3  ...........T....
0010: 9B 94 A1 07 68 DD B6 FE   85 D8 C6 76 D3 DF E5 2B  ....h......v...+
0020: 52 CF 01 66 F5 70 75 FD   45 2B A2 00 00 46 C0 23  R..f.pu.E+...F.#
0030: C0 27 00 3C C0 25 C0 29   00 67 00 40 C0 09 C0 13  .'.<.%.).g.@....
0040: 00 2F C0 04 C0 0E 00 33   00 32 C0 2B C0 2F 00 9C  ./.....3.2.+./..
0050: C0 2D C0 31 00 9E 00 A2   C0 08 C0 12 00 0A C0 03  .-.1............
0060: C0 0D 00 16 00 13 C0 07   C0 11 00 05 C0 02 C0 0C  ................
0070: 00 04 00 FF 01 00 00 6E   00 0A 00 34 00 32 00 17  .......n...4.2..
0080: 00 01 00 03 00 13 00 15   00 06 00 07 00 09 00 0A  ................
0090: 00 18 00 0B 00 0C 00 19   00 0D 00 0E 00 0F 00 10  ................
00A0: 00 11 00 02 00 12 00 04   00 05 00 14 00 08 00 16  ................
00B0: 00 0B 00 02 01 00 00 0D   00 1A 00 18 06 03 06 01  ................
00C0: 05 03 05 01 04 03 04 01   03 03 03 01 02 03 02 01  ................
00D0: 02 02 01 01 00 00 00 0E   00 0C 00 00 09 68 75 62  .............hub
00E0: 69 63 2E 63 6F 6D                                  ic.com
[Raw read]: length = 5
0000: 15 03 00 00 02                                     .....
[Raw read]: length = 2
0000: 02 46                                              .F
main, READ: SSLv3 Alert, length = 2
main, RECV TLSv1.2 ALERT:  fatal, protocol_version
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLException: Received fatal alert: protocol_version

No exception is thrown if I try to access e.g. https://google.com. So it guess SSL with Java cannot be completely broken on my system but it has to do with the combination with hubic.com.

The error protocol_version is not very helpful, but in this question it is suggested that my client uses another protocol version than the server (I guess "server and client could not agree on a protocol" would be more accurate).

How do I figure out which protocol versions the server will agree on and how do I enable those in my client? And should I worry about the issue (e.g. like does hubic only allow an old unsupported protocol? (Firefox certainly does not complain about anything unsecure).

4条回答
家丑人穷心不美
2楼-- · 2020-05-19 10:27

HttpClient can take an SSLContext for its SSLConnectionSocketFactory.

You can set the appropriate TLS version in the properties for the SSLContext with the getInstance static method.

Something like SSLContext context = SSLContext.getInstance("TLSv1");

If you need to force just one protocol (as getInstance can return one that supports multiple protocols), you can use the setEnabledProtocols method (which takes a String[]) on the context you retrieved using getInstance.

查看更多
爱情/是我丢掉的垃圾
3楼-- · 2020-05-19 10:32

It looks like you are not using java 1.8

In Java 1.8 the default TLS protocol version is v1.2, whereas in Java 1.6,1.7 default is TLS1.0. As you can see in logs ClientHello, TLSv1.2 it means you are either using java 1.6 or 1.7 now you can either switch to 1.8 or Just add

static { System.setProperty("https.protocols", "TLSv1.2"); }

in your application class before main class keeping you current java version
.. hope this helps !!

查看更多
戒情不戒烟
4楼-- · 2020-05-19 10:33

I see from the debug that Java does a TLS1.2 handshake instead of the more common SSLv23 handshake:

main, WRITE: TLSv1.2 Handshake, length = 225
[Raw write]: length = 230
0000: 16 03 03 00
         ^^^^^ - TLS1.2 (SSL3.3)

The server itself can do only TLS1.0 and fails to just announce this older version. I'm not familiar with Java, but you either need set the protocol version to TLSv1 or SSLv23 to speak with this server.

The following code would set only TLSv1 with Apache HttpClient:

HttpClientBuilder
  .create()
  .setSslcontext(SSLContexts.custom().useProtocol("TLSv1").build())
  .build()
  .execute(new HttpGet("https://hubic.com"));

EDIT to include question from comment:

If you say that the server "fails to just announce this older version", does that mean that the server is misconfigured? In this case, why don't Firefox&Chromium have any problems?

If the client announces TLS1.2 in the ClientHello and the server can do only TLS1.0 it should announce this, i.e. reply with TLS1.0. The client can then close the connection if TLS1.0 is not good enough or continue with TLS1.0. But, in this case the server just told the client that it does not like this version and closed the connection. Firefox and others instead do a SSLv23 announcement, where they do a TLS1.0 handshake but also announce the best protocol version they support. This usually works good for older servers starting from SSL3.0 but also for newer servers.

You can check the behavior of the server with a recent Perl/IO::Socket::SSL and this script.

$ perl analyze-ssl.pl hubic.com
-- hubic.com port 443
 * maximum SSL version  : TLSv1 (SSLv23)
 * supported SSL versions with handshake used and preferred cipher(s):
   * handshake protocols ciphers
   * SSLv23    TLSv1     AES256-SHA
   * TLSv1_2   FAILED: SSL connect attempt failed error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version number
   * TLSv1_1   FAILED: SSL connect attempt failed error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version number
   * TLSv1     TLSv1     AES256-SHA
   * SSLv3     FAILED: SSL connect attempt failed because of handshake problems error:1409442E:SSL routines:SSL3_READ_BYTES:tlsv1 alert protocol version

Here you can see, that the hosts supports SSLv23 and TLSv1 handshakes, but not the used TLSv1_2 handshake.

查看更多
欢心
5楼-- · 2020-05-19 10:39

I have also come across this issue. Certain sites are not accessible, throwing the mysterious: javax.net.ssl.SSLException: Received fatal alert: protocol_version

I have tried to mend it, following some of the hints given here, but without success. At one point the usual thought “it used to work before..”, really started nagging me.

Initially I had assumed something had changed in the site I tried to connect to. However, as this is a legacy kind of site, it wasn’t so likely. So, what else could it be..? At one point I thought “Java version”. Unlikely, but maybe worth a try.

As it is, I can get the content from previously error-throwing sites, if I compile my code with SDK 1.6.0_25. Newer versions gives me problems: 1.7.0_51, and 1.8.0.

I have boiled it down to the smallest piece possible, if effect reproducing the one-liner initially posted by “Yankee” above. I have used the same line, including the same URL.

Compiling with SDK 1.6 it works.

I am not sufficiently skilled in Java and SSL to understand the root issue behind this. But, someone ought to be able to put the code side by side, and track it down..

This may save someone a few wasted hours.

查看更多
登录 后发表回答