如何在带有Apache HttpClient的Java 6中使用TLS 1.2? [英] How can I use TLS 1.2 in Java 6 with an Apache HttpClient?

查看:279
本文介绍了如何在带有Apache HttpClient的Java 6中使用TLS 1.2?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Apache HttpClient 3.5和Spring Web Services 2.1.0进行Java 6项目.

I'm working on a Java 6 project using Apache HttpClient 3.5 and Spring Web Services 2.1.0.

我的Spring WebServicesTemplate正在使用apache HttpClient发送WebServices请求.但是,我正在联系的服务已经淘汰了TLS 1.0,转而使用TLS 1.2. Java 6不支持TLS 1.2.我被带到bouncycastle,应该给我TLS 1.2支持.

My Spring WebServicesTemplate is sending WebServices requests using an apache HttpClient. However, the service that I am contacting has phased out TLS 1.0 in favor of TLS 1.2. Java 6 does not support TLS 1.2. I was led to bouncycastle, which should give me TLS 1.2 support.

如何将Bouncycastle与Spring或HttpClient集成在一起,以便可以发送支持TLS 1.2的请求?我找到了提供扩展的SSLSocketFactory的解决方案.但是,HttpClient仅接受SSLConnectionSocketFactory.

How can I integrate bouncycastle with Spring or my HttpClient, so that I can send requests that support TLS 1.2? I have found a solution which provides an extended SSLSocketFactory. However, HttpClient only accepts SSLConnectionSocketFactory.

从短期来看,升级到Java 8是不可行的,但是如果有人确认可以解决我的问题,我可以将它作为长期优先事项.

Upgrading to Java 8 is not feasible in the short term, but I can make it a long-term priority if someone can confirm that it would fix my issue.

推荐答案

我提出了一个不需要升级到Java 8的解决方案.作为免责声明,我对https安全性了解甚少,而且我敢肯定有一些知识渊博的人可能会注意到的问题.此方法需要使用内置的HttpsURLConnection,如果您习惯使用Unirest甚至Apache HttpClient之类的话,这是非常原始的.

I have come up with a solution that does not require upgrading to Java 8. As a disclaimer, I know very little about https security, and I'm sure there are some issues that a more knowledgeable person may notice. This method requires using the built-in HttpsURLConnection, which is very primitive if you're used to using things like Unirest, or even apache HttpClient.

首先,您需要将BouncyCastle添加到pom.

First you need to add BouncyCastle to you pom.

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.54</version>
</dependency>

然后,您将创建SSLSocketFactory的扩展.警告!此套接字工厂将接受所有证书,因此使用时,后果自负.

Then you will create an extension of SSLSocketFactory. Warning! This socket factory will accept all certificates, so use at your own risk.

import java.io.*;
import java.net.UnknownHostException;
import java.security.*;
import java.security.cert.*;
import java.util.*;

import javax.net.ssl.*;
import javax.security.cert.X509Certificate;

import org.bouncycastle.crypto.tls.*;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class TLSSocketConnectionFactory extends SSLSocketFactory {

    static {
        if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
            Security.addProvider(new 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(), new     SecureRandom());

        return _createSSLSocket(host, tlsClientProtocol);
    }

    @Override public String[] getDefaultCipherSuites() { return null; }
    @Override public String[] getSupportedCipherSuites() { return null; }
    @Override public Socket createSocket(String host, int port) throws IOException, UnknownHostException { throw new UnsupportedOperationException(); }
    @Override public Socket createSocket(InetAddress host, int port) throws IOException { throw new UnsupportedOperationException(); }
    @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 { throw new UnsupportedOperationException(); }

    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() { 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 { 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; }
                    @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() {

                    @SuppressWarnings("unchecked")
                    @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);
                        dos.writeByte(0);
                        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 {
                                    KeyStore ks = _loadKeyStore();

                                    CertificateFactory cf = CertificateFactory.getInstance("X.509");
                                    List<java.security.cert.Certificate> certs = new LinkedList<java.security.cert.Certificate>();
                                    boolean trustedCertificate = false;
                                    for ( org.bouncycastle.asn1.x509.Certificate c : serverCertificate.getCertificateList()) {
                                        java.security.cert.Certificate cert = cf.generateCertificate(new ByteArrayInputStream(c.getEncoded()));
                                        certs.add(cert);

                                        String alias = ks.getCertificateAlias(cert);
                                        if(alias != null) {
                                            if (cert instanceof java.security.cert.X509Certificate) {
                                                try {
                                                    ( (java.security.cert.X509Certificate) cert).checkValidity();
                                                    trustedCertificate = true;
                                                } catch(CertificateExpiredException cee) {
                                                   // Accept all the certs!
                                                }
                                            }
                                        } else {
                                            // Accept all the certs!
                                        }

                                    }
                                    if (!trustedCertificate) {
                                        // Accept all the certs!
                                    }
                                    peertCerts = certs.toArray(new java.security.cert.Certificate[0]);
                                } catch (Exception ex) {
                                    ex.printStackTrace();
                                    throw new IOException(ex);
                                }
                            }

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

                            private KeyStore _loadKeyStore() throws Exception {
                                FileInputStream trustStoreFis = null;
                                try {
                                    KeyStore localKeyStore = null;

                                    String trustStoreType = System.getProperty("javax.net.ssl.trustStoreType")!=null?System.getProperty("javax.net.ssl.trustStoreType"):KeyStore.getDefaultType();
                                    String trustStoreProvider = System.getProperty("javax.net.ssl.trustStoreProvider")!=null?System.getProperty("javax.net.ssl.trustStoreProvider"):"";

                                    if (trustStoreType.length() != 0) {
                                        if (trustStoreProvider.length() == 0) {
                                            localKeyStore = KeyStore.getInstance(trustStoreType);
                                        } else {
                                            localKeyStore = KeyStore.getInstance(trustStoreType, trustStoreProvider);
                                        }

                                        char[] keyStorePass = null;
                                        String str5 = System.getProperty("javax.net.ssl.trustStorePassword")!=null?System.getProperty("javax.net.ssl.trustStorePassword"):"";

                                        if (str5.length() != 0) {
                                            keyStorePass = str5.toCharArray();
                                        }

                                        localKeyStore.load(trustStoreFis, keyStorePass);

                                        if (keyStorePass != null) {
                                            for (int i = 0; i < keyStorePass.length; i++) {
                                                keyStorePass[i] = 0;
                                            }
                                        }
                                    }
                                    return localKeyStore;
                                } finally {
                                    if (trustStoreFis != null) {
                                        trustStoreFis.close();
                                    }
                                }
                            }
                        };
                    }

                });
            } // startHandshake
        };
    }
}

接下来,您需要使用新的套接字工厂.如果使用Spring处理Web服务调用,则可以扩展现有的HttpUrlConnectionMessageSender以便为您发送调用.只需确保在您的spring配置中更新您的消息发送方bean,即可使用此类.

Next, you need to use your new socket factory. If you are using Spring to handle your Web Services calls, you can extend the existing HttpUrlConnectionMessageSender in order to send your calls for you. Just make sure to update your message sender bean in your spring config to use this class.

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

import javax.net.ssl.HttpsURLConnection;

import org.springframework.ws.transport.WebServiceConnection;
import org.springframework.ws.transport.http.*;


public class HttpsUrlConnectionMessageSender extends HttpUrlConnectionMessageSender {

    @Override
    public WebServiceConnection createConnection(URI uri) throws IOException {

        URL url = uri.toURL();
        URLConnection connection = url.openConnection();
        if (!(connection instanceof HttpsURLConnection)) {
            throw new HttpTransportException("URI [" + uri + "] is not an HTTPS URL");
        } else {
            HttpsURLConnection httpsURLConnection = (HttpsURLConnection) connection;
            httpsURLConnection.setSSLSocketFactory(new TLSSocketConnectionFactory());
            prepareConnection(httpsURLConnection);
            return new HttpsUrlConnection(httpsURLConnection);
        }
    }

    private static class HttpsUrlConnection extends HttpUrlConnection {
        private HttpsUrlConnection(HttpsURLConnection connection) {
            super(connection);
        }
    }
}

或者,如果您不使用Spring或Rest,则可以像上面的类中一样手动创建HttpsURLConnection,并使用outputstream发送消息.

Alternatively, if you are not using Spring, or using Rest, you can manually create an HttpsURLConnection as is done in the class above, and send your messages using the outputstream.

请注意,如果您与之通信的服务使用cookie,则需要设置一个系统范围的cookie管理器.但是,Java 6 Cookie管理器存在很多错误.您可能需要从Java 8 CookieManager复制源代码,以便Cookie可以正常工作.

Beware that if the service you are communication with uses cookies, you will need to set a system-wide cookie manager. However, the Java 6 cookie manager is bug-ridden. You may need to copy the source-code from the Java 8 CookieManager in order for your cookies to work.

if (CookieHandler.getDefault() == null) {
    CookieHandler.setDefault(new CookieManager());
}

这篇关于如何在带有Apache HttpClient的Java 6中使用TLS 1.2?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆