How to use TLS 1.2 in Java 6
Asked Answered
S

9

52

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?

Strang answered 27/10, 2015 at 9:27 Comment(3)
Java 6 is also stuck at 1024-bit DH moduli, IIRC. After logjam, it probably won't be able to connect to a well configured server. If possible, you should probably move on to another client platform.Witherspoon
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: github.com/mozilla/server-side-tls/issues/107)Lara
Java 6? Don't. Just DON'T. Using it on any public-facing system is reckless. There are 25 or so known easily-exploitable REMOTE vulnerabilities in the last publicly-available version of Java 1.6: web.archive.org/web/20160422142813/http://www.cvedetails.com/… And there are probably more than that because Java 6 went out of public support almost a decade ago.Trutko
L
45

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 jar files bcprov-jdk15to18-1.71.jar and bctls-jdk15to18-1.71.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%.

Laflamme answered 9/4, 2020 at 6:38 Comment(16)
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)Scabble
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 ./ )Laflamme
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.Ionize
This solution worked perfectly for me just followed the steps and that's it.United
I have skipped the step 3. But done others. Now I am getting nullpointer exception at CoreSecureRandom<init> . Any solutions without 3? (can't download files due to certain restrictions)Alsworth
Unfortunately, This step is mandatory to make the SSL work properly. The standard Java installation contains certain limitations because of the policies prohibiting the use of a key with a size that exceeds certain values ie. 128 bits for AES. Skiping step 3 you will not have the SSL fully functional for all websites using https.Laflamme
Just FYI; this also works for Java 1.7 as well.Liederman
There is an error when I try this in Weblogic 10.3.6. <Nov 7, 2022 6:44:22 AM UTC> <Critical> <WebLogicServer> <BEA-000386> <Server su bsystem failed. Reason: java.lang.NoClassDefFoundError: java/util/concurrent/Con currentLinkedDeque java.lang.NoClassDefFoundError: java/util/concurrent/ConcurrentLinkedDeque at org.bouncycastle.jcajce.provider.drbg.DRBG$EntropyDaemon.<init>(Unkno wn Source)Bridge
It seems you have a problem with the application server classloader. One of the Core Java class (java.util.concurrent.ConcurrentLinkedDeque) is not available at runtime. Make sure that the JVM you are running is the JDK 1.6. You can also try to run it using older versions of Bouncy Castle and see if it works.Laflamme
java.lang.NoClassDefFoundError: java/util/concurrent/ConcurrentLinkedDeque at org.bouncycastle.jcajce.provider.drbg.DRBG$EntropyDaemon.<init> at ... at org.bouncycastle.jcajce.provider.drbg.DRBG$Mappings.configure at org.bouncycastle.jce.provider.BouncyCastleProvider.loadServiceClass at org.bouncycastle.jce.provider.BouncyCastleProvider.loadAlgorithms at org.bouncycastle.jce.provider.BouncyCastleProvider.setup at ... at org.bouncycastle.jce.provider.BouncyCastleProvider.<init>() ... at java.security.KeyFactory.getInstance(KeyFactory.java:142) ConcurrentLinkedDeque is JDK 1.7+Bellbella
Try running KeyFactory factory = KeyFactory.getInstance("RSA"); with approach above and you will likely hit that java.lang.NoClassDefFoundError: java/util/concurrent/ConcurrentLinkedDeque exception on JDK 1.6 BouncyCastle 1.7.2 was pulling in JDK 1.7 class See:- github.com/bcgit/bc-java/commit/… and: github.com/bcgit/bc-java/issues/1295 Reverting to 1.7.1 builds or anything newer than 1.7.2 should solve the problemBellbella
Thanks TodayGuessWhat for the feedback, much appreciated. Already fixed! :-)Laflamme
This solution worked for me after adding bcutil-jdk15to18-175.jar along with bcprov-jdk15to18-1.71.jar and bctls-jdk15to18-1.71.jarUnhallow
I also had to add bcutil-*.jar to make it work, just like @Unhallow said. The 3 files may be downloaded here: bouncycastle.org/latest_releases.htmlBoldface
This post is a gem. Starting with these instructions I was able to get TLS 1.3 into an existing 20-year-old Java 6 application. I didn't think that was going to be possible. I did deviate slightly, using the later 176 BouncyCastle .jars, plus I also needed bcutil and bcprov-ext, but this post was the key to understanding the basics. Thank you.Edra
For me, also need to add bcpkix-jdk15to18-177.jar and change ssl.KeyManagerFactory.algorithm=PKIX in java.security, GCM will fail though.Palladio
L
27

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.)

Lara answered 27/10, 2015 at 11:4 Comment(1)
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..! .-)Pedo
P
18

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

Pedo answered 3/11, 2015 at 9:51 Comment(8)
If you prefer you can use raw HTTP commands this way #8172302 ..... 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());Pedo
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?Sieve
It worked, thanks. Really appreciate your answer, I was going nuts already before I found your solution.Gunpowder
@Pedo - We have similar issue with JDK 1.6u26 and tried to use this solution but got same error. Any idea what might be wrong?Constable
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.Bhutan
Lifesaver! Worked like a charm!!Soak
note that all these throws UnsupportedOperationException will have to go away - e.g. getLocalPrincipal() is actually called at some point by external code. it's enough to return null to bypass that - but I am not sure at what cost. It will work, though.Congressman
With which version of bouncycastle does this work? It does not compile with v1.77Panettone
F
17

Java 6, now support TLS 1.2, check out below

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

Florio answered 10/10, 2016 at 15:37 Comment(2)
Whilst this may theoretically answer the question, it would be preferable to include the essential parts of the answer here, and provide the link for reference.Pastry
Looks like this version is available to only those who has a support contract.Starlet
P
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());
Pedo answered 27/10, 2015 at 18:20 Comment(7)
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) ?Strang
The full samples are in this uri: #8172302Pedo
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 TSLClientProtocolPedo
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.Strang
Ooh...that's quite different!! , Maybe you can put an apache web server on frontend (serverfault.com/questions/314858/…) to serve the tomcat (that u could mantain in jdk 1.6). Sorry ._)Pedo
thank for your answer. it couldn't solve with bouncyCastle?Strang
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-Pedo
W
3

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/

Note: In case you cannot change the service-client code/config so that it targets the localhost domain, you can always play with hosts file and translate the the remote domain to the proxy's ip. But this has a catch. The reverse-proxy specifically will need to resolve the same domain to the original service ip. You can achieve this by moving the proxy to a different machine (with no hosts file entry) or by dockerizing it and utilizing the --add-host feature (or extra_hosts in docker-compose ).

Weald answered 21/1, 2019 at 16:53 Comment(2)
Saved my day, could not migrate code from Java 6, so it was really nice stumbling on this answer.Dysphemia
This answer has worked for me. However, I got following error. Invalid command 'SSLProxyEngine', perhaps misspelled or defined by a module not included in the server configuration Resolved by installing 'mod ssl' yum install mod_ssl in RHELBoles
M
1

I think that the solution of @Azimuts (https://mcmap.net/q/342753/-how-to-use-tls-1-2-in-java-6) 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();

    }

}

}

Mezereum answered 11/10, 2019 at 15:18 Comment(1)
Correct, thanx SalvatorePedo
H
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();
        }
    }
    
Holophrastic answered 5/10, 2020 at 23:27 Comment(0)
L
0

another BouncyCastle example. Just using bcprov-jdk15to18, bctls-jdk15to18, bcutil-jdk15to18, did the work for our old 1.6 client application.

UPDATE 1: BC version 1.71;

UPDATE 2: BC version 1.73, fix provider reference.

public static void main(String[] args) throws Exception {

    //put BC providers in runtime context
    if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
        BouncyCastleProvider provider = new BouncyCastleProvider();
        Security.addProvider(provider);
        // have to chain both BC providers,  so it doesn't conflict with JVM's default
        Security.addProvider(new BouncyCastleJsseProvider(provider));
    }

    //create an empty trust manager
    TrustManager[] trustManager = new TrustManager[] { new X509TrustManager() {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
        public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {}
        public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {}
    } };

    //initialize SSLContext 
    SSLContext sslContext = SSLContext.getInstance("TLSv1.2",  BouncyCastleJsseProvider.PROVIDER_NAME);        
    sslContext.init(null, trustManager, new SecureRandom());
    
    //connect and print data
    URL url = new URL("https://stackoverflow.com");
    HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
    connection.setSSLSocketFactory(sslContext.getSocketFactory());        
    connection.setRequestMethod("GET");
    InputStream returnStream = connection.getInputStream();        
    for (int ch; (ch = returnStream.read()) != -1; ) {
        System.out.print((char) ch);
    }
    returnStream.close();
    connection.disconnect();
}
Lowercase answered 20/10, 2021 at 15:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.