DummySSLSocketFactory.java
/*
* Copyright (c) 2014 Wael Chatila / Icegreen Technologies. All Rights Reserved.
* This software is released under the Apache license 2.0
*/
package com.icegreen.greenmail.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Random;
import static com.icegreen.greenmail.util.DummySSLServerSocketFactory.addAnonCiphers;
/**
* DummySSLSocketFactory - NOT SECURE
*/
public class DummySSLSocketFactory extends SSLSocketFactory {
protected static final Logger log = LoggerFactory.getLogger(DummySSLSocketFactory.class);
private final SSLSocketFactory factory;
public DummySSLSocketFactory() {
try {
SSLContext sslcontext = SSLContext.getInstance("TLS");
sslcontext.init(null,
new TrustManager[]{new DummyTrustManager()},
null);
factory = sslcontext.getSocketFactory();
} catch (Exception ex) {
log.error("Can not create and initialize SSL", ex);
throw new IllegalStateException("Can not create and initialize SSL", ex);
}
}
public static SocketFactory getDefault() {
return new DummySSLSocketFactory();
}
private Socket addAnonCipher(Socket socket) {
SSLSocket ssl = (SSLSocket) socket;
ssl.setEnabledCipherSuites(addAnonCiphers(ssl.getEnabledCipherSuites()));
return ssl;
}
@Override
public Socket createSocket()
throws IOException {
final Socket socket = factory.createSocket();
trySetFakeRemoteHost(socket);
return addAnonCipher(socket);
}
@Override
public Socket createSocket(Socket socket, String s, int i, boolean flag)
throws IOException {
return addAnonCipher(factory.createSocket(socket, s, i, flag));
}
@Override
public Socket createSocket(InetAddress inaddr, int i,
InetAddress inaddr1, int j) throws IOException {
return addAnonCipher(factory.createSocket(inaddr, i, inaddr1, j));
}
@Override
public Socket createSocket(InetAddress inaddr, int i)
throws IOException {
return addAnonCipher(factory.createSocket(inaddr, i));
}
@Override
public Socket createSocket(String s, int i, InetAddress inaddr, int j)
throws IOException {
return addAnonCipher(factory.createSocket(s, i, inaddr, j));
}
@Override
public Socket createSocket(String s, int i) throws IOException {
return addAnonCipher(factory.createSocket(s, i));
}
@Override
public String[] getDefaultCipherSuites() {
return factory.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return factory.getSupportedCipherSuites();
}
/**
* We set the host name of the remote machine because otherwise the SSL implementation is going
* to try to do a reverse lookup to find out the host name for the host which is really slow.
* Of course we don't know the host name of the remote machine so we just set a fake host name that is unique.
* <p/>
* This forces the SSL stack to do key negotiation every time we connect to a host but is still much faster
* than doing the reverse hostname lookup. The negotiation is caused by the fact that the SSL stack remembers
* a trust relationship with a host. If we connect to the same host twice this relationship is reused. Since
* we set the host name to a random value this reuse never happens.
*
* @param socket Socket to set host on
*/
private static void trySetFakeRemoteHost(Socket socket) {
try {
final Method setHostMethod = socket.getClass().getMethod("setHost", String.class);
String fakeHostName = "greenmailHost" + new BigInteger(130, new Random()).toString(32);
setHostMethod.invoke(socket, fakeHostName);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
log.debug("Could not set fake remote host. SSL connection setup may be slow.");
}
}
}