0

I'm struggling with an exception trying to connect to an https site. My code is in Java. It works form my laptop but not from my Linux server and I am not sure how to debug this.

I have retrieved the SSL certificate and imported to the cacerts truststore.

The Java code is the following

        System.setProperty("javax.net.debug", "ssl");

        String cacerts_file = System.getProperty("java.home")
                + "/lib/security/cacerts".replace('/', File.separatorChar);

        System.out.println(System.getProperty("javax.net.ssl.trustStore"));
        System.out.println("cacerts_file: " + cacerts_file);

        System.out.println(System.getProperty("javax.net.ssl.trustStore"));

        KeyStore ks = KeyStore.getInstance("JKS");
        FileInputStream in2 = new FileInputStream(cacerts_file);
        ks.load(in2, "changeit".toCharArray());

        System.out.println(ks.containsAlias("badoojira"));
        Enumeration<String> lAliases = ks.aliases();
        while (lAliases.hasMoreElements()) {
            String lAlias = (String) lAliases.nextElement();
            System.out.println(lAlias);
        }

        javax.net.ssl.KeyManagerFactory lKeyManagerFactory = javax.net.ssl.KeyManagerFactory
                .getInstance("SunX509");
        lKeyManagerFactory.init(ks, "changeit".toCharArray());
        javax.net.ssl.SSLContext lSSLContext = javax.net.ssl.SSLContext.getInstance("TLS");
        lSSLContext.init(lKeyManagerFactory.getKeyManagers(), null, null);
        SSLSocketFactory lSSLSocketFactory = lSSLContext.getSocketFactory();
        javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(lSSLSocketFactory);
        SSLSocket socket = (SSLSocket) lSSLSocketFactory
                .createSocket("wiki.badoojira.com", 443); 
        String[] suites = socket.getSupportedCipherSuites();
        socket.setEnabledCipherSuites(suites);

        // start handshake
        socket.startHandshake();

I have verified in the server with keystore command that the cacerts pointed by System.getProperty("java.home") + "/lib/security/cacerts".replace('/', File.separatorChar) has the actual certificate by calling a "keystore -list".

The Exception is:

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:1718)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:962)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1143)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1170)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1154)
at com.corp.GetStatusPage.oneMoreTest(GetStatusPage.java:105)
at com.corp.GetStatusPage.main(GetStatusPage.java:35)

With a debug Trace (edited)

    cacerts_file: /usr/lib64/jvm/java-1.7.0-sun-1.7.0/jre/lib/security/cacerts
    default truststore: /usr/lib64/jvm/java-1.7.0-sun-1.7.0/jre/lib/security/cacerts
    null
    true

    digicertassuredidrootca
    trustcenterclass2caii
    thawtepremiumserverca
    certifjira.com <<-- My certificate

    [Edited - removed all other default certificates aliases]

    trustStore is: /usr/lib64/jvm/java-1.7.0-sun-1.7.0/jre/lib/security/cacerts
    trustStore type is : jks
    trustStore provider is :
    init truststore
    adding as trusted cert:
      Subject: CN=SwissSign Platinum CA - G2, O=SwissSign AG, C=CH
      Issuer:  CN=SwissSign Platinum CA - G2, O=SwissSign AG, C=CH
      Algorithm: RSA; Serial number: 0x4eb200670c035d4f
      Valid from Wed Oct 25 08:36:00 UTC 2006 until Sat Oct 25 08:36:00 UTC 2036

    adding as trusted cert:
      Subject: EMAILADDRESS=personal-freemail@thawte.com, CN=Thawte Personal Freemail CA, OU=Certification Services Division, O=Thawte Consulting, L=Cape Town, ST=Western Cape, C=ZA
      Issuer:  EMAILADDRESS=personal-freemail@thawte.com, CN=Thawte Personal Freemail CA, OU=Certification Services Division, O=Thawte Consulting, L=Cape Town, ST=Western Cape, C=ZA
      Algorithm: RSA; Serial number: 0x123df0e7da2a2247a43889e08aeec967
      Valid from Mon Jan 01 00:00:00 UTC 1996 until Fri Jan 01 23:59:59 UTC 2021

    adding as trusted cert:
      Subject: EMAILADDRESS=server-certs@thawte.com, CN=Thawte Server CA, OU=Certification Services Division, O=Thawte Consulting cc, L=Cape Town, ST=Western Cape, C=ZA
      Issuer:  EMAILADDRESS=server-certs@thawte.com, CN=Thawte Server CA, OU=Certification Services Division, O=Thawte Consulting cc, L=Cape Town, ST=Western Cape, C=ZA
      Algorithm: RSA; Serial number: 0x34a4fff630af4ca53c331742a1946675
      Valid from Thu Aug 01 00:00:00 UTC 1996 until Fri Jan 01 23:59:59 UTC 2021

    adding as trusted cert:
      Subject: CN=*.certifjira.com, O=Trading Limited, L=London, ST=United Kingdom, C=GB
      Issuer:  CN=VeriSign Class 3 Secure Server CA - G3, OU=Terms of use at https://www.verisign.com/rpa (c)10, OU=VeriSign Trust Network, O="VeriSign, Inc.", C=US
      Algorithm: RSA; Serial number: 0x62a8e5628239c977eab16142cf0e8e0f
      Valid from Tue May 27 00:00:00 UTC 2014 until Thu May 28 23:59:59 UTC 2015

    [Edited to remove default certificates]

    trigger seeding of SecureRandom
    done seeding SecureRandom
    %% No cached client session
    *** ClientHello, TLSv1
    RandomCookie:  GMT: 1415190323 bytes = { 8, 10, 86, 52, 89, 227, 192, 166, 138, 175, 232, 157, 182, 160, 237, 133, 188, 63, 103, 151, 97, 195, 110, 180, 183, 28, 103, 245 }
    Session ID:  {}
    Cipher Suites: [SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_RC4_128_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_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, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_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_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, SSL_RSA_WITH_NULL_MD5, SSL_RSA_WITH_NULL_SHA, TLS_ECDH_ECDSA_WITH_NULL_SHA, TLS_ECDH_RSA_WITH_NULL_SHA, TLS_ECDHE_ECDSA_WITH_NULL_SHA, TLS_ECDHE_RSA_WITH_NULL_SHA, SSL_DH_anon_WITH_RC4_128_MD5, TLS_DH_anon_WITH_AES_128_CBC_SHA, SSL_DH_anon_WITH_3DES_EDE_CBC_SHA, SSL_DH_anon_WITH_DES_CBC_SHA, TLS_ECDH_anon_WITH_RC4_128_SHA, TLS_ECDH_anon_WITH_AES_128_CBC_SHA, TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, SSL_DH_anon_EXPORT_WITH_RC4_40_MD5, SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA, TLS_ECDH_anon_WITH_NULL_SHA, TLS_KRB5_WITH_RC4_128_SHA, TLS_KRB5_WITH_RC4_128_MD5, TLS_KRB5_WITH_3DES_EDE_CBC_SHA, TLS_KRB5_WITH_3DES_EDE_CBC_MD5, TLS_KRB5_WITH_DES_CBC_SHA, TLS_KRB5_WITH_DES_CBC_MD5, TLS_KRB5_EXPORT_WITH_RC4_40_SHA, TLS_KRB5_EXPORT_WITH_RC4_40_MD5, TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA, TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5]
    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]
    ***
    main, WRITE: TLSv1 Handshake, length = 213
    main, WRITE: SSLv2 client hello message, length = 227
    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

Many thanks for your help.

DavidU
  • 1
  • 1
  • 3

2 Answers2

0
  1. Your javax.net.ssl.trustStore settings merely implement what is already the default. Remove them.

  2. A keystore isn't a truststore. Unless you have voilated the Java truststore by adding your own private key and certificate to it, the keystore you specify should be different from the truststore.

  3. You don't need a keystore at all unless the server you're connecting to requires a client certificate. So fix or remove this.

  4. You need to paste the exact exception and stack trace into your question for further assistance to be possible.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • I simplified the code, remove elements metioned, added the stacktrace and the debug info from ssl. – DavidU Nov 05 '14 at 12:42
0

Thanks to some questions here I could find out that the enabled protocols on my 2 environments where different by adding to my code the following:

     String[] lEnabledProtocols = socket.getEnabledProtocols();
     for (int i = 0; i < lEnabledProtocols.length; i++) {
         String lProtocol = lEnabledProtocols[i];
         System.out.println("\t" + lProtocol);
     }

This showed that in the working environment I was only getting SSLv3, TLSv1 while in the one failing the handshake I had SSLv2Hello, SSLv3, TLSv1. So I tried to set specifically the enabled protocols.

        String[] lMyProtocols = { "SSLv3", "TLSv1" };
        socket.setEnabledProtocols(lMyProtocols);

This proved to work for me. Hope there is no downside to explicitly set these protocols.

DavidU
  • 1
  • 1
  • 3
  • No immediate downside, but over time this may make your app out of date. E.g. if the problem was as I guessed client=tomcat on j6, and someday that gets upgraded to j8, and the server implements above TLS1 -- and *if* the server is java given it rejected v2hello that suggests it is at least j7 which (on server) *does* support 1.1 and 1.2 -- *then* this won't get the newer protocol(s). There are now attacks on SSL3 and TLS1.0 which may or may not actually matter to your app, but may still matter to auditors firewalls and such. ... – dave_thompson_085 Nov 08 '14 at 11:24
  • ... to "futureproof" I would `.getEnabledProtocols`, *if* `SSLv2Hello` is present remove it (using a temp ArrayList) and set that. This would enforce *minimum* SSL3, but let JVM increase the maximum. – dave_thompson_085 Nov 08 '14 at 11:27