/*
* Copyright 2011 Blazebit
*/
package com.blazebit.mail.transport;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.GeneralSecurityException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
/**
*
* @author Christian Beikov
* @since 0.1.2
*/
public class MailSSLSocketFactory extends SSLSocketFactory {
private boolean trustAllHosts = false;
private List<String> trustedHosts = new ArrayList<String>();
private List<String> temporaryTrustedHosts = new ArrayList<String>();
private SSLContext sslContext;
private KeyManager[] keyManagers;
private TrustManager[] trustManagers;
private SecureRandom secureRandom;
private SSLSocketFactory delegateFactory = null;
public MailSSLSocketFactory() throws GeneralSecurityException {
this("TLS");
}
public MailSSLSocketFactory(String protocol)
throws GeneralSecurityException {
trustAllHosts = false;
sslContext = SSLContext.getInstance(protocol);
keyManagers = null;
trustManagers = new TrustManager[] { new MailTrustManager() };
secureRandom = null;
createDelegateFactory();
}
private synchronized void createDelegateFactory()
throws KeyManagementException {
sslContext.init(keyManagers, trustManagers, secureRandom);
delegateFactory = (SSLSocketFactory) sslContext.getSocketFactory();
}
public synchronized KeyManager[] getKeyManagers() {
return (KeyManager[]) keyManagers.clone();
}
public synchronized void setKeyManagers(KeyManager[] keyManagers)
throws GeneralSecurityException {
this.keyManagers = (KeyManager[]) keyManagers.clone();
createDelegateFactory();
}
public synchronized SecureRandom getSecureRandom() {
return secureRandom;
}
public synchronized void setSecureRandom(SecureRandom secureRandom)
throws GeneralSecurityException {
this.secureRandom = secureRandom;
createDelegateFactory();
}
public synchronized TrustManager[] getTrustManagers() {
return trustManagers;
}
public synchronized void setTrustManagers(TrustManager[] trustManagers)
throws GeneralSecurityException {
this.trustManagers = trustManagers;
createDelegateFactory();
}
public synchronized boolean isTrustAllHosts() {
return trustAllHosts;
}
public synchronized void setTrustAllHosts(boolean trustAllHosts) {
this.trustAllHosts = trustAllHosts;
}
public synchronized String[] getTrustedHosts() {
return trustedHosts.toArray(new String[0]);
}
public synchronized void setTrustedHosts(String[] trustedHosts) {
this.trustedHosts = Arrays.asList(trustedHosts);
}
public synchronized void removeTrustedHost(String trustedHost) {
this.trustedHosts.remove(trustedHost);
this.temporaryTrustedHosts.remove(trustedHost);
}
public synchronized void addTrustedHost(String host, boolean permanently) {
if (!permanently) {
temporaryTrustedHosts.add(host);
} else {
trustedHosts.add(host);
}
}
public synchronized void clearTemporaryTrustedHosts() {
temporaryTrustedHosts.clear();
}
public synchronized List<String> getTemporaryTrustedHosts() {
return Collections.unmodifiableList(temporaryTrustedHosts);
}
@Override
public synchronized Socket createSocket(Socket socket, String s, int i,
boolean flag) throws IOException {
return delegateFactory.createSocket(socket, s, i, flag);
}
@Override
public synchronized String[] getDefaultCipherSuites() {
return delegateFactory.getDefaultCipherSuites();
}
@Override
public synchronized String[] getSupportedCipherSuites() {
return delegateFactory.getSupportedCipherSuites();
}
@Override
public synchronized Socket createSocket() throws IOException {
return delegateFactory.createSocket();
}
@Override
public synchronized Socket createSocket(InetAddress inetAddress, int i,
InetAddress inetAddress1, int j) throws IOException {
return delegateFactory.createSocket(inetAddress, i, inetAddress1, j);
}
@Override
public synchronized Socket createSocket(InetAddress inetAddress, int i)
throws IOException {
return delegateFactory.createSocket(inetAddress, i);
}
@Override
public synchronized Socket createSocket(String s, int i,
InetAddress inetAddress, int j) throws IOException,
UnknownHostException {
return delegateFactory.createSocket(s, i, inetAddress, j);
}
@Override
public synchronized Socket createSocket(String s, int i)
throws IOException, UnknownHostException {
return delegateFactory.createSocket(s, i);
}
private class MailTrustManager implements X509TrustManager {
private X509TrustManager delegateTrustManager = null;
private MailTrustManager() throws GeneralSecurityException {
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init((KeyStore) null);
delegateTrustManager = (X509TrustManager) tmf.getTrustManagers()[0];
}
@Override
public void checkClientTrusted(X509Certificate[] certs, String authType)
throws CertificateException {
delegateTrustManager.checkClientTrusted(certs, authType);
}
@Override
public void checkServerTrusted(X509Certificate[] certs, String authType)
throws CertificateException {
if (isTrustAllHosts())
return;
String host = null;
for (String part : certs[0].getSubjectX500Principal().getName()
.split(",")) {
String[] keyValue = part.split("=");
if ("CN".equals(keyValue[0])) {
host = keyValue[1];
break;
}
}
for (String trustedHost : getTemporaryTrustedHosts()) {
if (host.equals(trustedHost))
return;
}
for (String trustedHost : getTrustedHosts()) {
if (host.equals(trustedHost))
return;
}
delegateTrustManager.checkServerTrusted(certs, authType);
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return delegateTrustManager.getAcceptedIssuers();
}
}
}