package org.xnio.ssl;
import static org.xnio._private.Messages.msg;
import java.lang.reflect.InvocationTargetException;
import java.net.InetSocketAddress;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.TrustManager;
import org.xnio.OptionMap;
import org.xnio.Options;
import org.xnio.Sequence;
public final class JsseSslUtils {
private JsseSslUtils() {
}
public static SSLContext createSSLContext(OptionMap optionMap) throws NoSuchProviderException, NoSuchAlgorithmException, KeyManagementException {
return createSSLContext(null, null, null, optionMap);
}
public static SSLContext createSSLContext(KeyManager[] keyManagers, TrustManager[] trustManagers, SecureRandom secureRandom, OptionMap optionMap) throws NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException {
final String provider = optionMap.get(Options.SSL_PROVIDER);
final String protocol = optionMap.get(Options.SSL_PROTOCOL);
final SSLContext sslContext;
if (protocol == null) {
return SSLContext.getDefault();
} else if (provider == null) {
sslContext = SSLContext.getInstance(protocol);
} else {
sslContext = SSLContext.getInstance(protocol, provider);
}
if (keyManagers == null) {
final Sequence<Class<? extends KeyManager>> keyManagerClasses = optionMap.get(Options.SSL_JSSE_KEY_MANAGER_CLASSES);
if (keyManagerClasses != null) {
final int size = keyManagerClasses.size();
keyManagers = new KeyManager[size];
for (int i = 0; i < size; i ++) {
keyManagers[i] = instantiate(keyManagerClasses.get(i));
}
}
}
if (trustManagers == null) {
final Sequence<Class<? extends TrustManager>> trustManagerClasses = optionMap.get(Options.SSL_JSSE_TRUST_MANAGER_CLASSES);
if (trustManagerClasses != null) {
final int size = trustManagerClasses.size();
trustManagers = new TrustManager[size];
for (int i = 0; i < size; i ++) {
trustManagers[i] = instantiate(trustManagerClasses.get(i));
}
}
}
sslContext.init(keyManagers, trustManagers, secureRandom);
sslContext.getClientSessionContext().setSessionCacheSize(optionMap.get(Options.SSL_CLIENT_SESSION_CACHE_SIZE, 0));
sslContext.getClientSessionContext().setSessionTimeout(optionMap.get(Options.SSL_CLIENT_SESSION_TIMEOUT, 0));
sslContext.getServerSessionContext().setSessionCacheSize(optionMap.get(Options.SSL_SERVER_SESSION_CACHE_SIZE, 0));
sslContext.getServerSessionContext().setSessionTimeout(optionMap.get(Options.SSL_SERVER_SESSION_TIMEOUT, 0));
return sslContext;
}
@SuppressWarnings("TryWithIdenticalCatches")
private static <T> T instantiate(Class<T> clazz) {
try {
return clazz.getConstructor().newInstance();
} catch (InstantiationException e) {
throw msg.cantInstantiate(clazz, e);
} catch (IllegalAccessException e) {
throw msg.cantInstantiate(clazz, e);
} catch (NoSuchMethodException e) {
throw msg.cantInstantiate(clazz, e);
} catch (InvocationTargetException e) {
throw msg.cantInstantiate(clazz, e.getCause());
}
}
public static SSLEngine createSSLEngine(SSLContext sslContext, OptionMap optionMap, InetSocketAddress peerAddress) {
final SSLEngine engine = sslContext.createSSLEngine(
optionMap.get(Options.SSL_PEER_HOST_NAME, peerAddress.getHostString()),
optionMap.get(Options.SSL_PEER_PORT, peerAddress.getPort())
);
engine.setUseClientMode(true);
engine.setEnableSessionCreation(optionMap.get(Options.SSL_ENABLE_SESSION_CREATION, true));
final Sequence<String> cipherSuites = optionMap.get(Options.SSL_ENABLED_CIPHER_SUITES);
if (cipherSuites != null) {
final Set<String> supported = new HashSet<String>(Arrays.asList(engine.getSupportedCipherSuites()));
final List<String> finalList = new ArrayList<String>();
for (String name : cipherSuites) {
if (supported.contains(name)) {
finalList.add(name);
}
}
engine.setEnabledCipherSuites(finalList.toArray(new String[finalList.size()]));
}
final Sequence<String> protocols = optionMap.get(Options.SSL_ENABLED_PROTOCOLS);
if (protocols != null) {
final Set<String> supported = new HashSet<String>(Arrays.asList(engine.getSupportedProtocols()));
final List<String> finalList = new ArrayList<String>();
for (String name : protocols) {
if (supported.contains(name)) {
finalList.add(name);
}
}
engine.setEnabledProtocols(finalList.toArray(new String[finalList.size()]));
}
return engine;
}
}