43

It seems that Java 6 supports TLS up to v1.0, is there any way to use TLS 1.2 in Java 6?

Maybe a patch or a particular update of Java 6 will have support for it?

Zoran Regvart
  • 4,398
  • 20
  • 34
alex
  • 429
  • 1
  • 4
  • 4
  • Java 6 is also stuck at 1024-bit DH moduli, IIRC. After [logjam](http://stackoverflow.com/a/30706878), it probably won't be able to connect to a well configured server. If possible, you should probably move on to another client platform. – jww Nov 07 '16 at 17:17
  • Actually, Java 6 & 7 now support for DH ephemeral keys up to 2048 bits, starting with JRE 6U105 (aka1.6.0_105) and 7u91 (aka 1.7.0_91). (Source: https://github.com/mozilla/server-side-tls/issues/107) – Stephen C Mar 05 '18 at 09:56

8 Answers8

25

Public Oracle Java 6 releases do not support TLSv1.2. Paid-for releases of Java 6 (post-EOL) might. (UPDATE - TLSv1.1 is available for Java 1.6 from update 111 onwards; source)

Contact Oracle sales.

Other alternatives are:

  • Use an alternative JCE implementation such as Bouncy Castle. See this answer for details on how to do it. It changes the default SSLSocketFactory implementation, so that your application will use BC transparently. (Other answers show how to use the BC SSLSocketFactory implementation explicitly, but that approach will entail modifying application or library code that that is opening sockets.)

  • Use an IBM Java 6 ... if available for your platform. According to "IBM SDK, Java Technology Edition fixes to mitigate against the POODLE security vulnerability (CVE-2014-3566)":

    "TLSv1.1 and TLSv1.2 are available only for Java 6 service refresh 10, Java 6.0.1 service refresh 1 (J9 VM2.6), and later releases."


However, I'd advise upgrading to a Java 11 (now). Java 6 was EOL'd in Feb 2013, and continuing to use it is potentially risky. Free Oracle Java 8 is EOL for many use-cases. (Tell or remind the boss / the client. They need to know.)

Stephen C
  • 632,615
  • 86
  • 730
  • 1,096
  • 2
    One note about this .All samples i have seen using Bouncy are based on sending raw HTTP commands... That's a bit difficult to integrate into a working/production program. The best way obviously, would be upgrading the JVM (depending the aplication server, IBM JVM, f.e, could not be available..in a Oracle WLS environment). Bellow i explain a workaround, just using a customized SSL SocketConnectionFactory based on Bouncy. If anybody found a solution, based not just sendind raw HTTP Commands, please share for the procommons..! .-) – Azimuts Oct 28 '15 at 09:03
18

After a few hours of playing with the Oracle JDK 1.6, I was able to make it work without any code change. The magic is done by Bouncy Castle to handle SSL and allow JDK 1.6 to run with TLSv1.2 by default. In theory, it could also be applied to older Java versions with eventual adjustments.

  1. Download the latest Java 1.6 version from the Java Archive Oracle website
  2. Uncompress it on your preferred path and set your JAVA_HOME environment variable
  3. Update the JDK with the latest Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 6
  4. Download the Bounce Castle files bcprov-jdk15to18-165.jar and bctls-jdk15to18-165.jar and copy them into your ${JAVA_HOME}/jre/lib/ext folder
  5. Modify the file ${JAVA_HOME}/jre/lib/security/java.security commenting out the providers section and adding some extra lines
    # Original security providers (just comment it)
    # security.provider.1=sun.security.provider.Sun
    # security.provider.2=sun.security.rsa.SunRsaSign
    # security.provider.3=com.sun.net.ssl.internal.ssl.Provider
    # security.provider.4=com.sun.crypto.provider.SunJCE
    # security.provider.5=sun.security.jgss.SunProvider
    # security.provider.6=com.sun.security.sasl.Provider
    # security.provider.7=org.jcp.xml.dsig.internal.dom.XMLDSigRI
    # security.provider.8=sun.security.smartcardio.SunPCSC

    # Add the Bouncy Castle security providers with higher priority
    security.provider.1=org.bouncycastle.jce.provider.BouncyCastleProvider
    security.provider.2=org.bouncycastle.jsse.provider.BouncyCastleJsseProvider
    
    # Original security providers with different priorities
    security.provider.3=sun.security.provider.Sun
    security.provider.4=sun.security.rsa.SunRsaSign
    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

    # Here we are changing the default SSLSocketFactory implementation
    ssl.SocketFactory.provider=org.bouncycastle.jsse.provider.SSLSocketFactoryImpl

Just to make sure it's working let's make a simple Java program to download files from one URL using https.

import java.io.*;
import java.net.*;


public class DownloadWithHttps {

    public static void main(String[] args) {
        try {
            URL url = new URL(args[0]);
            System.out.println("File to Download: " + url);
            String filename = url.getFile();
            File f = new File(filename);
            System.out.println("Output File: " + f.getName());
            BufferedInputStream in = new BufferedInputStream(url.openStream());
            FileOutputStream fileOutputStream = new FileOutputStream(f.getName());
            int bytesRead;
            byte dataBuffer[] = new byte[1024];

            while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) {
                fileOutputStream.write(dataBuffer, 0, bytesRead);
            }
            fileOutputStream.close();

        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }
}

Now, just compile the DownloadWithHttps.java program and execute it with your Java 1.6


${JAVA_HOME}/bin/javac DownloadWithHttps.java
${JAVA_HOME}/bin/java DownloadWithHttps https://repo1.maven.org/maven2/org/apache/commons/commons-lang3/3.10/commons-lang3-3.10.jar

Important note for Windows users: This solution was tested in a Linux OS, if you are using Windows, please replace the ${JAVA_HOME} by %JAVA_HOME%.

Wellington Souza
  • 1,612
  • 17
  • 28
  • I am using Java JDK 6u45 64-bit. How to solve the random source issue, please? Please, see the stack trace: C:\>java DownloadWithHttps 03/07/2020 13:15:35 03/07/2020 13:15:36 org.bouncycastle.jsse.provider.ProvTrustManagerFactorySpi getDefaultTrustStore INFO: Initializing with trust store at path: C:\Desenvolvimento\Ferramentas\JDKs\JDK6\jre\lib\security\cacerts Exception in thread "main" java.lang.InternalError: unable to open random source at org.bouncycastle.jcajce.provider.drbg.DRBG$URLSeededSecureRandom$1.run(Unknown Source) – cviniciusm Jul 03 '20 at 16:24
  • I just tested on Windows 10 and it's also working to download the file from the maven repository like in the example. Please, do not skip any step, especially step number 3. Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 6. And if it did not work yet, then you can try to fake the secure random on Windows passing the JVM parameter via command line: `-Djava.security.egd=file:/dev/./urandom` (note the extra `./` ) – Wellington Souza Jul 06 '20 at 02:13
  • Thanks! It worked for me! In my case, i was compiling a project with java 6 and maven 3.2.5 and when downloading from maven central repo, an "Received fatal alert: protocol_version" error was occurrying, due to not using TLS 1.2. – Afaria Oct 20 '20 at 15:52
  • 1
    This solution worked perfectly for me just followed the steps and that's it. – Harshal Nov 16 '20 at 09:49
17

Here a TLSConnection Factory:

package test.connection;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.Principal;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;

import javax.net.ssl.HandshakeCompletedEvent;
import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSessionContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.security.cert.X509Certificate;

import org.bouncycastle.crypto.tls.Certificate;
import org.bouncycastle.crypto.tls.CertificateRequest;
import org.bouncycastle.crypto.tls.DefaultTlsClient;
import org.bouncycastle.crypto.tls.ExtensionType;
import org.bouncycastle.crypto.tls.TlsAuthentication;
import org.bouncycastle.crypto.tls.TlsClientProtocol;
import org.bouncycastle.crypto.tls.TlsCredentials;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

/**
 * This Class enables TLS V1.2  connection based on BouncyCastle Providers.
 * Just to use: 
 * URL myurl = new URL( "http:// ...URL tha only Works in TLS 1.2);
   HttpsURLConnection  con = (HttpsURLConnection )myurl.openConnection();
   con.setSSLSocketFactory(new TSLSocketConnectionFactory());  
 * @author AZIMUTS
 *
 */
public class TSLSocketConnectionFactory extends SSLSocketFactory {  


//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Adding Custom BouncyCastleProvider
/////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
   static {
    if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null)
        Security.addProvider(new BouncyCastleProvider());
    }   
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//HANDSHAKE LISTENER
/////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
    public class TLSHandshakeListener implements HandshakeCompletedListener {
        @Override
        public void handshakeCompleted(HandshakeCompletedEvent event) { 

        }
    }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//SECURE RANDOM
/////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
    private SecureRandom _secureRandom = new SecureRandom();

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Adding Custom BouncyCastleProvider
/////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
    @Override
    public Socket createSocket(Socket socket, final String host, int port, boolean arg3)
            throws IOException {
        if (socket == null) {
            socket = new Socket();
        }
        if (!socket.isConnected()) {
            socket.connect(new InetSocketAddress(host, port));
        }

        final TlsClientProtocol tlsClientProtocol = new TlsClientProtocol(socket.getInputStream(), socket.getOutputStream(), _secureRandom);
        return _createSSLSocket(host, tlsClientProtocol);


      }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SOCKET FACTORY  METHODS  
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    @Override
    public String[] getDefaultCipherSuites() {      
        return null;
    }

    @Override
    public String[] getSupportedCipherSuites(){ 
        return null;
    }

    @Override
    public Socket createSocket(String host, int port) throws IOException,UnknownHostException{  
        return null;
    }

    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException { 
        return null;
    }

    @Override
    public Socket createSocket(String host, int port, InetAddress localHost,
            int localPort) throws IOException, UnknownHostException {   
        return null;
    }

    @Override
    public Socket createSocket(InetAddress address, int port,
            InetAddress localAddress, int localPort) throws IOException{    
        return null;
    }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//SOCKET CREATION
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    private SSLSocket _createSSLSocket(final String host , final TlsClientProtocol tlsClientProtocol) {
     return new SSLSocket() {            
        private java.security.cert.Certificate[] peertCerts;

         @Override
          public InputStream getInputStream() throws IOException {
              return tlsClientProtocol.getInputStream();
          }

          @Override
          public OutputStream getOutputStream() throws IOException {
              return tlsClientProtocol.getOutputStream();
          }

          @Override
          public synchronized void close() throws IOException {         
             tlsClientProtocol.close();
          }

           @Override
           public void addHandshakeCompletedListener(HandshakeCompletedListener arg0) {         

           }

            @Override
            public boolean getEnableSessionCreation() {         
                return false;
            }

            @Override
            public String[] getEnabledCipherSuites() {          
                return null;
            }

            @Override
            public String[] getEnabledProtocols() {
                // TODO Auto-generated method stub
                return null;
            }

            @Override
            public boolean getNeedClientAuth(){         
                return false;
            }

            @Override
            public SSLSession getSession() {
                   return new SSLSession() {

                    @Override
                    public int getApplicationBufferSize() {                 
                        return 0;
                    }

                    @Override
                    public String getCipherSuite() {
                         throw new UnsupportedOperationException();
                    }

                    @Override
                    public long getCreationTime() {
                         throw new UnsupportedOperationException();
                    }

                    @Override
                    public byte[] getId() {
                         throw new UnsupportedOperationException();
                    }

                    @Override
                    public long getLastAccessedTime() {
                         throw new UnsupportedOperationException();
                    }

                    @Override
                    public java.security.cert.Certificate[] getLocalCertificates() {
                         throw new UnsupportedOperationException();
                    }

                    @Override
                    public Principal getLocalPrincipal() {
                         throw new UnsupportedOperationException();
                    }

                    @Override
                    public int getPacketBufferSize() {
                         throw new UnsupportedOperationException();
                    }

                    @Override
                    public X509Certificate[] getPeerCertificateChain()
                            throws SSLPeerUnverifiedException {
                        // TODO Auto-generated method stub
                        return null;
                    }

                    @Override
                    public java.security.cert.Certificate[] getPeerCertificates()throws SSLPeerUnverifiedException {
                         return peertCerts;
                    }

                    @Override
                    public String getPeerHost() {
                         throw new UnsupportedOperationException();
                    }

                    @Override
                    public int getPeerPort() {                      
                        return 0;
                    }

                    @Override
                    public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
                      return null;
                         //throw new UnsupportedOperationException();

                    }

                    @Override
                    public String getProtocol() {
                         throw new UnsupportedOperationException();
                    }

                    @Override
                    public SSLSessionContext getSessionContext() {
                         throw new UnsupportedOperationException();
                    }

                    @Override
                    public Object getValue(String arg0) {
                         throw new UnsupportedOperationException();
                    }

                    @Override
                    public String[] getValueNames() {
                         throw new UnsupportedOperationException();
                    }

                    @Override
                    public void invalidate() {
                         throw new UnsupportedOperationException();

                    }

                    @Override
                    public boolean isValid() {
                         throw new UnsupportedOperationException();
                    }

                    @Override
                    public void putValue(String arg0, Object arg1) {
                         throw new UnsupportedOperationException();

                    }

                    @Override
                    public void removeValue(String arg0) {
                         throw new UnsupportedOperationException();

                    }

                   };
            }


            @Override
            public String[] getSupportedProtocols() {       
                return null;
            }

            @Override
            public boolean getUseClientMode() {             
                return false;
            }

            @Override
            public boolean getWantClientAuth() {

                return false;
            }

            @Override
            public void removeHandshakeCompletedListener(HandshakeCompletedListener arg0) {             

            }

            @Override
            public void setEnableSessionCreation(boolean arg0) {


            }

            @Override
            public void setEnabledCipherSuites(String[] arg0) {         

            }

            @Override
            public void setEnabledProtocols(String[] arg0) {


            }

            @Override
            public void setNeedClientAuth(boolean arg0) {           

            }

            @Override
            public void setUseClientMode(boolean arg0) {            

            }

            @Override
            public void setWantClientAuth(boolean arg0) {               

            }

            @Override
            public String[] getSupportedCipherSuites() {            
                return null;
            }
            @Override
            public void startHandshake() throws IOException {
                  tlsClientProtocol.connect(new DefaultTlsClient() {                       
                         @Override
                          public Hashtable<Integer, byte[]> getClientExtensions() throws IOException {
                                Hashtable<Integer, byte[]> clientExtensions = super.getClientExtensions();
                                if (clientExtensions == null) {
                                    clientExtensions = new Hashtable<Integer, byte[]>();
                                }

                                //Add host_name
                                byte[] host_name = host.getBytes();

                                final ByteArrayOutputStream baos = new ByteArrayOutputStream();
                                final DataOutputStream dos = new DataOutputStream(baos);
                                dos.writeShort(host_name.length + 3); // entry size
                                dos.writeByte(0); // name type = hostname
                                dos.writeShort(host_name.length);
                                dos.write(host_name);
                                dos.close();
                                clientExtensions.put(ExtensionType.server_name, baos.toByteArray());
                                return clientExtensions;
                        }

                        @Override
                        public TlsAuthentication getAuthentication()
                                throws IOException {
                            return new TlsAuthentication() {


                                @Override
                                public void notifyServerCertificate(Certificate serverCertificate) throws IOException {

                                  try {
                                        CertificateFactory cf = CertificateFactory.getInstance("X.509");
                                        List<java.security.cert.Certificate> certs = new LinkedList<java.security.cert.Certificate>();
                                        for ( org.bouncycastle.asn1.x509.Certificate c : serverCertificate.getCertificateList()) {                                          
                                            certs.add(cf.generateCertificate(new ByteArrayInputStream(c.getEncoded())));
                                        }
                                        peertCerts = certs.toArray(new java.security.cert.Certificate[0]);
                                    } catch (CertificateException e) {                                   
                                       System.out.println( "Failed to cache server certs"+ e);
                                       throw new IOException(e);
                                    }

                                }

                                @Override
                                public TlsCredentials getClientCredentials(CertificateRequest arg0)
                                        throws IOException {                                    
                                    return null;
                                }

                            };

                        }

                   });



            }




     };//Socket

    }
}

Remember that to prove this is, the best is to test against a website that exposes ONLY TLS 1.2. If the web exposes TLS 1.0, TLS 1.1 depending on the Java implementation will connect using tls 1.0, tls 1.1. Test it against a site that only exposes TLS 1.2. An example can be the NIST secure site https://www.nist.gov

Azimuts
  • 1,102
  • 3
  • 14
  • 33
  • 2
    If you prefer you can use raw HTTP commands this way http://stackoverflow.com/questions/8171802/using-bouncycastle-for-a-simple-https-query?lq=1 ..... But are raw http commands.... I thinks it's better to use HTTPSUrlconnection + customized SSLConnectionFactory : URL myurl = new URL( "http:// ...URL tha only Works in TLS 1.2); HttpsURLConnection con = (HttpsURLConnection )myurl.openConnection(); con.setSSLSocketFactory(new TSLSocketConnectionFactory()); – Azimuts Nov 03 '15 at 10:00
  • I am stuck with Java 5 and this seems to be the only solution. I see that alot of these methods are empty, throws exception or return nulls. Whats the purpose behind this? Do you have a working TLS connection factory implementation? – Saky Jun 13 '17 at 00:35
  • 1
    It worked, thanks. Really appreciate your answer, I was going nuts already before I found your solution. – Dmytro Pastovenskyi Jun 25 '18 at 13:08
  • @Azimuts - We have similar issue with JDK 1.6u26 and tried to use this solution but got same error. Any idea what might be wrong? – Ankur Raiyani Jun 27 '19 at 05:13
  • Thank you very much for this plug&play solution - it worked perfectly in my environment (Domino 9.0.1FP8). It would have taken me hours/days to get this to work - thanks for saving me that time. – xpages-noob Jul 03 '19 at 13:35
  • Lifesaver! Worked like a charm!! – tarares Sep 27 '19 at 19:15
17

Java 6, now support TLS 1.2, check out below

http://www.oracle.com/technetwork/java/javase/overview-156328.html#R160_121

David
  • 179
  • 1
  • 2
  • 7
    Whilst this may theoretically answer the question, [it would be preferable](//meta.stackoverflow.com/q/8259) to include the essential parts of the answer here, and provide the link for reference. – Bhargav Rao Oct 10 '16 at 15:43
  • 16
    Looks like this version is available to only those who has a support contract. – user872858 Sep 07 '17 at 20:41
6

You must create your own SSLSocketFactory based on Bouncy Castle. After to use it, pass to the common HttpsConnextion for using this customized SocketFactory.

1. First : Create a TLSConnectionFactory

Here one tips:

1.1 Extend SSLConnectionFactory

1.2 Override this method :

@Override 
public Socket createSocket(Socket socket, final String host, int port, boolean arg3)

This method will call the next internal method,

1.3 Implement an internal method _createSSLSocket(host, tlsClientProtocol);

Here you must create a Socket using TlsClientProtocol . The trick is override ...startHandshake() method calling TlsClientProtocol

 private SSLSocket _createSSLSocket(final String host , final TlsClientProtocol tlsClientProtocol) {
     return new SSLSocket() {    
       .... Override and implement SSLSocket methods,  particulary: 
            startHandshake() {
             }    
     }

     

Important : The full sample how to use TLS Client Protocol is well explained here: Using BouncyCastle for a simple HTTPS query

2. Second : Use this Customized SSLConnextionFactory on common HTTPSConnection.

This is important ! In other samples you can see into the web , u see hard-coded HTTP Commands....so with a customized SSLConnectionFactory u don't need nothing more...

  URL myurl = new URL( "http:// ...URL tha only Works in TLS 1.2);
  HttpsURLConnection  con = (HttpsURLConnection )myurl.openConnection();
  con.setSSLSocketFactory(new TSLSocketConnectionFactory());
Community
  • 1
  • 1
Azimuts
  • 1,102
  • 3
  • 14
  • 33
  • thanks. i'm using bouncyCastle in tomcat. so could you explain the solution in detail? or is there any sample or tutorial in customize BC to use TLS1.2(in java6) ? – alex Nov 03 '15 at 08:20
  • The full samples are in this uri: http://stackoverflow.com/questions/8171802/using-bouncycastle-for-a-simple-https-query – Azimuts Nov 03 '15 at 09:40
  • But...try to implement a customized SSLConnectionFactory (TLSConnectionFactory) , in the way i explain... Just begin to make a class that extends SSLConnectionFactory and override @Override public Socket createSocket(Socket socket, final String host, int port, boolean arg3) ...Just there call the TSLClientProtocol – Azimuts Nov 03 '15 at 09:42
  • 1
    I thing there is a misgiving. i don't want to connect to a server as a client. I looking to a way which allow me to response to client (browsers) using tls1.2. in other word I have my own webapp(deployed in tomcat) that has written by java6 and uses bouncycastle to response secured connections. but i wanna to upgrade TLSv1(which is support) to TLSv1.2 without upgrading java version. – alex Nov 03 '15 at 12:24
  • Ooh...that's quite different!! , Maybe you can put an apache web server on frontend (http://serverfault.com/questions/314858/how-to-enable-tls-1-1-and-1-2-with-openssl-and-apache) to serve the tomcat (that u could mantain in jdk 1.6). Sorry ._) – Azimuts Nov 03 '15 at 13:27
  • thank for your answer. it couldn't solve with bouncyCastle? – alex Nov 04 '15 at 05:11
  • Sorry, I don't know... Maybe the best would be to use an apache on front-end, so you would be "independent" to the application infraestructure (Tomcat), but maybe this is an architecture change to measure up- – Azimuts Nov 04 '15 at 07:45
1

In case you need to access a specific set of remote services you could use an intermediate reverse-proxy, to perform tls1.2 for you. This would save you from trying to patch or upgrade java1.6.

e.g. app -> proxy:http(5500)[tls-1.2] -> remote:https(443)

Configuration in its simplest form (one port per service) for apache httpd is:

Listen 127.0.0.1:5000
<VirtualHost *:5500>
    SSLProxyEngine On
    ProxyPass / https://remote-domain/
    ProxyPassReverse / https://remote-domain/
</VirtualHost>

Then instead of accessing https://remote-domain/ you access http://localhost:5500/

Marinos An
  • 6,191
  • 2
  • 35
  • 68
1

I think that the solution of @Azimuts (https://stackoverflow.com/a/33375677/6503697) is for HTTP only connection. For FTPS connection you can use Bouncy Castle with org.apache.commons.net.ftp.FTPSClient without the need for rewrite FTPS protocol.

I have a program running on JRE 1.6.0_04 and I can not update the JRE.

The program has to connect to an FTPS server that work only with TLS 1.2 (IIS server).

I struggled for days and finally I have understood that there are few versions of bouncy castle library right in my use case: bctls-jdk15on-1.60.jar and bcprov-jdk15on-1.60.jar are ok, but 1.64 versions are not.

The version of apache commons-net is 3.1 .

Following is a small snippet of code that should work:

import java.io.ByteArrayOutputStream;
import java.security.SecureRandom;
import java.security.Security;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.net.ftp.FTPSClient;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider;
import org.junit.Test;


public class FtpsTest {

// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {

    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return null;
    }

    public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
    }

    public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
    }
} };

@Test public void test() throws Exception {


    Security.insertProviderAt(new BouncyCastleProvider(), 1);
    Security.addProvider(new BouncyCastleJsseProvider());


    SSLContext sslContext = SSLContext.getInstance("TLS", new BouncyCastleJsseProvider());
    sslContext.init(null, trustAllCerts, new SecureRandom());
    org.apache.commons.net.ftp.FTPSClient ftpClient = new FTPSClient(sslContext);
    ByteArrayOutputStream out = null;
    try {

        ftpClient.connect("hostaname", 21);
        if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
            String msg = "Il server ftp ha rifiutato la connessione.";
            throw new Exception(msg);
        }
        if (!ftpClient.login("username", "pwd")) {
            String msg = "Il server ftp ha rifiutato il login con username:  username  e pwd:  password  .";
            ftpClient.disconnect();
            throw new Exception(msg);
        }


        ftpClient.enterLocalPassiveMode();
        ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
        ftpClient.setDataTimeout(60000);
        ftpClient.execPBSZ(0); // Set protection buffer size
        ftpClient.execPROT("P"); // Set data channel protection to private
        int bufSize = 1024 * 1024; // 1MB
        ftpClient.setBufferSize(bufSize);
        out = new ByteArrayOutputStream(bufSize);
        ftpClient.retrieveFile("remoteFileName", out);
        out.toByteArray();
    }
    finally {
        if (out != null) {
            out.close();
        }
        ftpClient.disconnect();

    }

}

}

1

I also got a similar error when forced to use TLS1.2 for java 6. And I handled it thanks to this library:

  1. Clone Source Code: https://github.com/tobszarny/ssl-provider-jvm16

  2. Add Main Class:

    public static void main(String[] args) throws Exception {
        try {
            String apiUrl = "https://domain/api/query?test=123";
    
            URL myurl = new URL(apiUrl);
            HttpsURLConnection con = (HttpsURLConnection) myurl.openConnection();
            con.setSSLSocketFactory(new TSLSocketConnectionFactory());
            int responseCode = con.getResponseCode();
            System.out.println("GET Response Code :: " + responseCode);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    
fcdt
  • 2,151
  • 5
  • 9
  • 24
Tran Hao
  • 11
  • 1