简体   繁体   中英

Handshake failure with Java when I try to do a POST

I try to contact *** and send some data using POST.

I use jersey-bundle-1.18.jar which I have imported into my Eclipse project. This is my code:

    Client client = Client.create();
    WebResource webResource = client.resource("https://somesite.com");
    MultivaluedMap<String, String> map = new MultivaluedMapImpl();
    map.putSingle("key_name", API_KEY_NAME);
    map.putSingle("key_value", API_KEY_VALUE);
    map.putSingle("message", "Test");
    map.putSingle("extension", "+0012345678");
    ClientResponse response = webResource.type("application/x-www-form-urlencoded")
                 .post(ClientResponse.class, map); // throws exception here
    return response.toString();

When I run my code I get javax.net.ssl.SSLHandshakeException. The certificate used by the site is from StartCom, and I don't think this CA is in Java's default truststore, at not least in Java 6, according to this poster

I ran my program with the JVM flag -Djavax.net.debug=all and this is what I got:

trigger seeding of SecureRandom
done seeding SecureRandom
Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA256
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_128_CBC_SHA256
Allow unsafe renegotiation: false
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
main, setSoTimeout(0) called
%% No cached client session
*** ClientHello, TLSv1
RandomCookie:  GMT: 1391505439 bytes = { 186, 52, 225, 5, 67, 137, 170, 128, 220, 41, 178, 86, 199, 17, 150, 190, 23, 47, 217, 126, 162, 34, 68, 40, 216, 221, 193, 108 }
Session ID:  {}
Cipher Suites: [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_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, 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, 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 server_name, server_name: [host_name: ***]
***
[write] MD5 and SHA1 hashes:  len = 176
0000: 01 00 00 AC 03 01 53 F1   B0 1F BA 34 E1 05 43 89  ......S....4..C.
0010: AA 80 DC 29 B2 56 C7 11   96 BE 17 2F D9 7E A2 22  ...).V...../..."
0020: 44 28 D8 DD C1 6C 00 00   2A C0 09 C0 13 00 2F C0  D(...l..*...../.
0030: 04 C0 0E 00 33 00 32 C0   07 C0 11 00 05 C0 02 C0  ....3.2.........
0040: 0C C0 08 C0 12 00 0A C0   03 C0 0D 00 16 00 13 00  ................
0050: 04 00 FF 01 00 00 59 00   0A 00 34 00 32 00 17 00  ......Y...4.2...
0060: 01 00 03 00 13 00 15 00   06 00 07 00 09 00 0A 00  ................
0070: 18 00 0B 00 0C 00 19 00   0D 00 0E 00 0F 00 10 00  ................
0080: 11 00 02 00 12 00 04 00   05 00 14 00 08 00 16 00  ................
main, WRITE: TLSv1 Handshake, length = 176
[Raw write]: length = 181
0000: 16 03 01 00 B0 01 00 00   AC 03 01 53 F1 B0 1F BA  ...........S....
0010: 34 E1 05 43 89 AA 80 DC   29 B2 56 C7 11 96 BE 17  4..C....).V.....
0020: 2F D9 7E A2 22 44 28 D8   DD C1 6C 00 00 2A C0 09  /..."D(...l..*..
0030: C0 13 00 2F C0 04 C0 0E   00 33 00 32 C0 07 C0 11  .../.....3.2....
0040: 00 05 C0 02 C0 0C C0 08   C0 12 00 0A C0 03 C0 0D  ................
0050: 00 16 00 13 00 04 00 FF   01 00 00 59 00 0A 00 34  ...........Y...4
0060: 00 32 00 17 00 01 00 03   00 13 00 15 00 06 00 07  .2..............
0070: 00 09 00 0A 00 18 00 0B   00 0C 00 19 00 0D 00 0E  ................
0080: 00 0F 00 10 00 11 00 02   00 12 00 04 00 05 00 14  ................
0090: 00 08 00 16 00 0B 00 02   01 00 00 00 00 17 00 15  ................
[Raw read]: length = 5
0000: 15 03 01 00 02                                     .....
[Raw read]: length = 2
0000: 02 28                                              .(
main, READ: TLSv1 Alert, length = 2
main, RECV TLSv1 ALERT:  fatal, handshake_failure
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
main, called close()
main, called closeInternal(true)
Exception in thread "main" com.sun.jersey.api.client.ClientHandlerException: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

What's wrong, and how can I make it work?

EDIT: As mentioned below, I downloaded Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files, but for Java 7, since this is the version of Java I'm using and copied the jar files to /lib/security as per instructions.

I ran the program again, and got stuck at another exception. I've copied a couple of rows from the Eclipse console:

%% Invalidated: [Session-1, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA] main, SEND TLSv1 ALERT: fatal, description = certificate_unknown main, WRITE: TLSv1 Alert, length = 2 [Raw write]: length = 7 0000: 15 03 01 00 02 02 2E ....... main, called closeSocket() main, handling exception: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

This time, it seems like the StartCom certificate in Java's truststore is missing at last. I'm sure it's possible to overcome this problem, but since I consider to deploy my code into a jar file that can be used by other people, I don't think it's a feasible solution to let people replace their JCE Policy files in order to use my library.

I was a bit nonplussed when I first encountered this error because I had actually executed about the same code before with successful results, but when I think about it, I used OpenJDK and not Oracle's proprietary JDK. When I used OpenJDK I didn't had the encryption problem either. So, it seems like I've two bad choices here:

1). Force users to switch their Java Development Kit to OpenJDK, or my service/library won't work.

2). Force users to replace the JCE Policy files of their JRE and import the StartCom certificate into Java's keystore, eg using keytool, or maybe I could load the certificate during runtime?

Is this somewhat correct?

EDIT2:

Here's how I created my own truststore with the certificates available at http://www.startssl.com/certs/ca-bundle.crt

try {
    // Read the certificate bundle from disk
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    Certificate ca = cf.generateCertificate(getClass().getResourceAsStream("ca-bundle.crt")); // the file ca-bundle.crt should be in the same folder as your .java files
    // Create a KeyStore containing our trusted CAs
    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    keyStore.load(null, null);
    keyStore.setCertificateEntry("ca", ca);
    // Create a TrustStore that trusts the CAs in our KeyStore
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmf.init(keyStore);
    // Create an SSLContext that uses our TrustManager
    sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, tmf.getTrustManagers(), null);
} catch (CertificateException | KeyStoreException | NoSuchAlgorithmException | KeyManagementException | IOException e) {
        e.printStackTrace();
}

It's now possible to communicate with the server securely. You can create a HttpClient with your custom SSLContext like this:

CloseableHttpClient client = HttpClients.custom().setSslcontext(sslContext).build();

Update your Java Cryptography Extension:

Java 6 http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html

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

The default JRE comes only with limited cryptographic strength because of the US law.


Edit: It seems the ROOT CA Certificate of StartCom isn't in the java trusted CA. Add it yourself using openssl to cacerts in the JRE (see Digital Certificate: How to import .cer file in to .truststore file ).

You are building a library, just put a notice somewhere in a txt file (README, HOWTO, FAQ, ...) for people with this problem to do the same with the root AC Certificate.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM