0

First of all, I premise that I am fully aware that Java 7 is EOL, vulnerable, extremely old and should not be used in 2023, but I need to mantain a legacy application which requires Java 7. I cannot upgrade it, so, please, read the full question (or jump to the next one) instead of commenting immediately with "Java 7 is old, upgrade it" just because there is "Java 7" in the title. Thank you for your understanding.


I have a legacy Java 7 application which sends some HTTPS requests to a server. Recently, that server changed its supported TLS ciphers so now all HTTP requests done from my Java application throw an exception.

This is a sample of the code I am using to send the HTTP requests:

URL url = new URL("https://precision.epayworldwide.com/up-interface");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String responseLine = reader.readLine();

while (responseLine != null)
{
    System.out.printf("%s\n", responseLine);
    responseLine = reader.readLine();
}

and this is the exception I get:

Exception in thread "main" 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:1943)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1059)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1294)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1321)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1305)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:523)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1296)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
    at Main.main(Main.java:17)

To try to fix this exception I have tried the following steps (as suggested by this answer):

  1. I have donwloaded bcprov-jdk15to18-175.jar from BouncyCastle and I have added this JAR in my jdk/jre/lib/ext directory.
  2. I have edited the jdk/jre/lib/security/java.security file placing org.bouncycastle.jce.provider.BouncyCastleProvider at the top of the list of providers:
#
# List of providers and their preference orders (see above):
#
security.provider.1=org.bouncycastle.jce.provider.BouncyCastleProvider
security.provider.2=sun.security.provider.Sun
security.provider.3=sun.security.rsa.SunRsaSign
security.provider.4=sun.security.ec.SunEC
security.provider.5=com.sun.net.ssl.internal.ssl.Provider
security.provider.6=com.sun.crypto.provider.SunJCE
security.provider.7=sun.security.jgss.SunProvider
security.provider.8=com.sun.security.sasl.Provider
security.provider.9=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.10=sun.security.smartcardio.SunPCSC
security.provider.11=sun.security.mscapi.SunMSCAPI

But I still get the handshake failure alert from the server.

I have also tried to add the bcutil-jdk15to18-175.jar to my jdk/jre/lib/ext directory (as suggested by a comment in the linked answer), but I still get the exception.

I have enabled TLS logging by adding the JVM argument -Djavax.net.debug=ssl:handshake:verbose and this is what I get:

trigger seeding of SecureRandom
done seeding SecureRandom
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 unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
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 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.2
RandomCookie:  GMT: 1670579945 bytes = { 154, 22, 251, 69, 138, 101, 239, 72, 131, 212, 72, 151, 61, 82, 28, 179, 11, 15, 212, 118, 164, 38, 59, 49, 139, 50, 122, 48 }
Session ID:  {}
Cipher Suites: [TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_RC4_128_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_RC4_128_MD5, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA]
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: [host_name: precision.epayworldwide.com]
***
main, WRITE: TLSv1.2 Handshake, length = 229
main, READ: TLSv1.2 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

It seems that the HttpURLConnection is not using the AES-GCM cipher (e.g. TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256), even though it should be implemented by the JARs I have added.

For the records, I have tested the server I am connecting to with this script and these are the supported ciphers:

Testing ECDHE-RSA-AES256-GCM-SHA384...YES
Testing DHE-RSA-AES256-GCM-SHA384...YES
Testing ECDHE-RSA-AES128-GCM-SHA256...YES
Testing DHE-RSA-AES128-GCM-SHA256...YES
Testing ECDHE-RSA-AES256-SHA384...YES
Testing ECDHE-RSA-AES128-SHA256...YES
Testing AES256-GCM-SHA384...YES

I am trying to support AES-GCM on my client because it's one of the ciphers supported by the server.

If possible, I would like to resolve this problem without changing the code (e.g. by explicitly setting the ciphers the HttpURLConnection should use).

Ricky Sixx
  • 581
  • 1
  • 10
  • 25
  • 3
    The bcprov+bcutil jars, accessed by the `BouncyCastleProvider` class, provide only cryptographic _primitives_, including AES-GCM. You are still using the Sun/Oracle/Open provider _for TLS_ (SunJSSE) which does not implement ciphersuites _containing_ AES-GCM. **For GCM you need to also use the bctls jar accessed by `org.bouncycastle.jsse.provider.BouncyCastleJsseProvider`.** However you should be able to use the 5th or 6th suite in your 'Testing' list, which are CBC suites, with 'standard' j7. – dave_thompson_085 Jun 21 '23 at 15:01
  • ... In particular TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 and/or TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 should work -- and they're listed as 'ignoring' in the debuglog, I think because they can't be used in protocols below TLSv1.2. Try `setEnabledProtocols` to `"TLSv1.2"` _only_ and see if that helps. – dave_thompson_085 Jun 21 '23 at 15:15
  • In fact now I look at the previous A you linked it already said for GCM in 7 to download _both_ bcprov and bctls and configure _both_ BouncyCastleProvider and BouncyCastleJsseProvider ! – dave_thompson_085 Jun 21 '23 at 15:22
  • @dave_thompson_085 My bad, I missed that part. Now I am getting another error, but I have opened another question for that. Thank you for your clarification about why both providers are needed (which is not explained in that answer). – Ricky Sixx Jun 21 '23 at 16:41

0 Answers0