You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by Apache Wiki <wi...@apache.org> on 2015/10/13 23:23:31 UTC
[Tomcat Wiki] Update of "tools/SSLUtils.java" by ChristopherSchultz
Dear Wiki user,
You have subscribed to a wiki page or wiki category on "Tomcat Wiki" for change notification.
The "tools/SSLUtils.java" page has been changed by ChristopherSchultz:
https://wiki.apache.org/tomcat/tools/SSLUtils.java
New page:
/*
* SSLUtils.java
*
* Contains useful SSL/TLS methods.
*
* Copyright (c) 2015 Christopher Schultz
*
* Christopher Schultz licenses this file to You under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.cert.CRL;
import java.security.cert.CRLException;
import java.security.cert.CertPathParameters;
import java.security.cert.CertStore;
import java.security.cert.CertStoreParameters;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.PKIXBuilderParameters;
import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate;
import java.util.Collection;
import javax.net.ssl.CertPathTrustManagerParameters;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.ManagerFactoryParameters;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
/**
* Lots of useful SSL-related goodies.
*
* @author Christopher Schultz
* @author Apache Software Foundation (some code adapted/lifted from Apache Tomcat).
*/
public class SSLUtils
{
public static void disableSSLHostnameVerification()
{
HostnameVerifier verifyEverything = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session)
{
return true;
}
};
HttpsURLConnection.setDefaultHostnameVerifier(verifyEverything);
}
private static final TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs,
String authType) {
// Trust all clients
}
public void checkServerTrusted(X509Certificate[] certs,
String authType) {
// Trust all servers
}
}
};
public static TrustManager[] getTrustAllCertsTrustManagers()
{
return trustAllCerts.clone();
}
/**
* Configures SSLSocketFactory for Java's HttpsURLConnection.
*/
public static void configureHttpsURLConnection(String protocol,
String[] sslEnabledProtocols,
String[] sslCipherSuites,
SecureRandom random,
TrustManager[] tms)
throws NoSuchAlgorithmException, KeyManagementException
{
HttpsURLConnection.setDefaultSSLSocketFactory(getSSLSocketFactory(protocol,
sslEnabledProtocols,
sslCipherSuites,
random,
tms));
}
/**
* Creates an SSLSocketFactory that supports only the specified protocols
* and ciphers.
*/
public static SSLSocketFactory getSSLSocketFactory(String protocol,
String[] sslEnabledProtocols,
String[] sslCipherSuites,
SecureRandom random,
TrustManager[] tms)
throws NoSuchAlgorithmException, KeyManagementException
{
SSLContext sc = SSLContext.getInstance(protocol);
// System.out.println("Wanted protocol: " + protocol);
// System.out.println("Got protocol: " + sc.getProtocol());
sc.init(null, tms, random);
SSLSocketFactory sf = sc.getSocketFactory();
if(null != sslEnabledProtocols
|| null != sslCipherSuites)
sf = new CustomSSLSocketFactory(sf,
sslEnabledProtocols,
sslCipherSuites);
return sf;
}
/**
* In order to customize the specific enabled protocols and cipher suites,
* a customized SSLSocketFactory must be used.
*
* This is just a wrapper around that customization.
*/
public static class CustomSSLSocketFactory
extends javax.net.ssl.SSLSocketFactory
{
private final String[] _sslEnabledProtocols;
private final String[] _sslCipherSuites;
private final SSLSocketFactory _base;
public CustomSSLSocketFactory(SSLSocketFactory base,
String[] sslEnabledProtocols,
String[] sslCipherSuites)
{
_base = base;
if(null == sslEnabledProtocols)
_sslEnabledProtocols = null;
else
_sslEnabledProtocols = sslEnabledProtocols.clone();
if(null == sslCipherSuites || 0 == sslCipherSuites.length)
_sslCipherSuites = getDefaultCipherSuites();
else if(1 == sslCipherSuites.length && "ALL".equalsIgnoreCase(sslCipherSuites[0]))
_sslCipherSuites = getSupportedCipherSuites();
else
_sslCipherSuites = sslCipherSuites.clone();
}
public String[] getDefaultCipherSuites() {
return _base.getDefaultCipherSuites();
}
public String[] getSupportedCipherSuites() {
return _base.getSupportedCipherSuites();
}
private SSLSocket customize(Socket s)
{
SSLSocket socket = (SSLSocket)s;
if(null != _sslEnabledProtocols)
socket.setEnabledProtocols(_sslEnabledProtocols);
socket.setEnabledCipherSuites(_sslCipherSuites);
return socket;
}
@Override
public Socket createSocket(Socket s,
String host,
int port,
boolean autoClose)
throws IOException
{
return customize(_base.createSocket(s, host, port, autoClose));
}
@Override
public Socket createSocket(String host, int port)
throws IOException, UnknownHostException
{
return customize(_base.createSocket(host, port));
}
@Override
public Socket createSocket(InetAddress host, int port)
throws IOException
{
return customize(_base.createSocket(host, port));
}
@Override
public Socket createSocket(String host, int port,
InetAddress localHost, int localPort)
throws IOException, UnknownHostException
{
return customize(_base.createSocket(host, port, localHost, localPort));
}
@Override
public Socket createSocket(InetAddress address, int port,
InetAddress localAddress, int localPort)
throws IOException
{
return customize(_base.createSocket(address, port, localAddress, localPort));
}
}
/**
* In order to customize the specific enabled protocols and cipher suites,
* a customized SSLSocketFactory must be used.
*
* This is just a wrapper around that customization.
*/
public static class CustomSSLServerSocketFactory
extends javax.net.ssl.SSLServerSocketFactory
{
private final String[] _sslEnabledProtocols;
private final String[] _sslCipherSuites;
private final SSLServerSocketFactory _base;
public CustomSSLServerSocketFactory(SSLServerSocketFactory base,
String[] sslEnabledProtocols,
String[] sslCipherSuites)
{
_base = base;
if(null == sslEnabledProtocols)
_sslEnabledProtocols = null;
else
_sslEnabledProtocols = sslEnabledProtocols.clone();
if(null == sslCipherSuites || 0 == sslCipherSuites.length)
_sslCipherSuites = getDefaultCipherSuites();
else if(1 == sslCipherSuites.length && "ALL".equalsIgnoreCase(sslCipherSuites[0]))
_sslCipherSuites = getSupportedCipherSuites();
else
_sslCipherSuites = sslCipherSuites.clone();
}
public String[] getDefaultCipherSuites() {
return _base.getDefaultCipherSuites();
}
public String[] getSupportedCipherSuites() {
return _base.getSupportedCipherSuites();
}
private SSLServerSocket customize(ServerSocket s)
{
SSLServerSocket socket = (SSLServerSocket)s;
if(null != _sslEnabledProtocols)
socket.setEnabledProtocols(_sslEnabledProtocols);
socket.setEnabledCipherSuites(_sslCipherSuites);
return socket;
}
@Override
public SSLServerSocket createServerSocket()
throws IOException
{
return customize(_base.createServerSocket());
}
@Override
public SSLServerSocket createServerSocket(int port)
throws IOException
{
return customize(_base.createServerSocket(port));
}
@Override
public SSLServerSocket createServerSocket(int port, int backlog)
throws IOException
{
return customize(_base.createServerSocket(port, backlog));
}
@Override
public SSLServerSocket createServerSocket(int port, int backlog, InetAddress ifAddress)
throws IOException
{
return customize(_base.createServerSocket(port, backlog, ifAddress));
}
}
/**
* Creates an SSLSocketFactory that supports only the specified protocols
* and ciphers.
*/
public static SSLServerSocketFactory getSSLServerSocketFactory(String protocol,
String[] sslEnabledProtocols,
String[] sslCipherSuites,
SecureRandom random,
TrustManager[] tms)
throws NoSuchAlgorithmException, KeyManagementException
{
SSLContext sc = SSLContext.getInstance(protocol);
// System.out.println("Wanted protocol: " + protocol);
// System.out.println("Got protocol: " + sc.getProtocol());
sc.init(null, tms, random);
SSLServerSocketFactory sf = sc.getServerSocketFactory();
if(null != sslEnabledProtocols
|| null != sslCipherSuites)
sf = new CustomSSLServerSocketFactory(sf,
sslEnabledProtocols,
sslCipherSuites);
return sf;
}
//
// All the code for loading TrustManagers was adapted from code in
// the Apache Tomcat project.
//
/**
* Gets an array of TrustManagers for the specified trust store
* and optional CRL file.
*
* @param trustStoreFilename
* @param trustStorePassword
* @param trustStoreType
* @param trustStoreProvider
* @param trustStoreAlgorithm
* @param maxCertificatePathLength
* @param crlFilename
*
* @return An array of TrustManagers
*
* @throws IOException
* @throws KeyStoreException
* @throws NoSuchProviderException
* @throws NoSuchAlgorithmException
* @throws CertificateException
* @throws InvalidAlgorithmParameterException
* @throws CRLException
*/
protected static TrustManager[] getTrustManagers(String trustStoreFilename,
String trustStorePassword,
String trustStoreType,
String trustStoreProvider,
String trustStoreAlgorithm,
Integer maxCertificatePathLength,
String crlFilename)
throws IOException, KeyStoreException, NoSuchProviderException, NoSuchAlgorithmException, CertificateException, InvalidAlgorithmParameterException, CRLException
{
KeyStore trustStore = getStore(trustStoreFilename,
trustStorePassword,
trustStoreType,
trustStoreProvider);
if(null == trustStoreAlgorithm)
trustStoreAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf =
TrustManagerFactory.getInstance(trustStoreAlgorithm);
if (null == crlFilename)
{
tmf.init(trustStore);
}
else
{
CertPathParameters params =
getParameters(trustStoreAlgorithm,
crlFilename,
maxCertificatePathLength,
trustStore);
ManagerFactoryParameters mfp =
new CertPathTrustManagerParameters(params);
tmf.init(mfp);
}
return tmf.getTrustManagers();
}
/**
* Return the initialization parameters for the TrustManager.
* Currently, only the default <code>PKIX</code> is supported.
*
* @param algorithm The algorithm to get parameters for.
* @param crlFilename The path to the CRL file.
* @param maxCertificateChainLength Optional maximum cert chain length.
* @param trustStore The configured TrustStore.
*
* @return The parameters including the TrustStore and any CRLs.
*
* @throws InvalidAlgorithmParameterException
* @throws KeyStoreException
* @throws IOException
* @throws CertificateException
* @throws CRLException
* @throws NoSuchAlgorithmException
*/
protected static CertPathParameters getParameters(String algorithm,
String crlFilename,
Integer maxCertificateChainLength,
KeyStore trustStore)
throws KeyStoreException, InvalidAlgorithmParameterException, CRLException, CertificateException, IOException, NoSuchAlgorithmException
{
CertPathParameters params = null;
if("PKIX".equalsIgnoreCase(algorithm)) {
PKIXBuilderParameters xparams =
new PKIXBuilderParameters(trustStore, new X509CertSelector());
Collection<? extends CRL> crls = getCRLs(crlFilename);
CertStoreParameters csp = new CollectionCertStoreParameters(crls);
CertStore store = CertStore.getInstance("Collection", csp);
xparams.addCertStore(store);
xparams.setRevocationEnabled(true);
if(maxCertificateChainLength != null)
xparams.setMaxPathLength(maxCertificateChainLength.intValue());
params = xparams;
} else {
throw new CRLException("CRLs not supported for type: " + algorithm);
}
return params;
}
/**
* Loads a collection of Certificate Revocation Lists (CRLs)
* from a file.
*
* @param crlFilename The file name of the CRL.
*
* @return A Collection of CRLs from the specified file.
*
* @throws IOException If the CRL file could not be loaded.
* @throws CRLException If the CRL list cannot be loaded.
* @throws CertificateException If there is a problem with one
* of the certificates in the revocation list.
*/
public static Collection<? extends CRL> getCRLs(String crlFilename)
throws IOException, CRLException, CertificateException
{
File crlFile = new File(crlFilename);
Collection<? extends CRL> crls = null;
InputStream is = null;
try
{
CertificateFactory cf = CertificateFactory.getInstance("X.509");
is = new FileInputStream(crlFile);
crls = cf.generateCRLs(is);
}
finally
{
if(is != null) try{ is.close(); }
catch(IOException ioe) { ioe.printStackTrace(); }
}
return crls;
}
/**
* Loads a keystore.
*
* @param storeFilename The file name of the keystore.
* @param storePassword The keystore password.
* @param storeType The type of the keystore.
* @param storeProvider Optional keystore provider.
*
* @return A KeyStore loaded from the specified file.
*
* @throws IOException If the file cannot be read.
* @throws KeyStoreException If the KeyStore cannot be read.
* @throws NoSuchProviderException If the provider is not recognized.
* @throws NoSuchAlgorithmException If the an algorithm used by the KeyStore is no recognized.
* @throws CertificateException If there is a problem with a certificate in the KeyStore.
*/
public static KeyStore getStore(String storeFilename,
String storePassword,
String storeType,
String storeProvider)
throws IOException, KeyStoreException, NoSuchProviderException, CertificateException, NoSuchAlgorithmException
{
KeyStore ks = null;
InputStream in = null;
try
{
if(null == storeProvider)
ks = KeyStore.getInstance(storeType);
else
ks = KeyStore.getInstance(storeType, storeProvider);
// TODO: Explicitly check for PKCS11?
in = new FileInputStream(storeFilename);
char[] storePass = null;
if (storePassword != null && !"".equals(storePassword))
storePass = storePassword.toCharArray();
ks.load(in, storePass);
return ks;
}
finally
{
if(null != in) try { in.close(); }
catch (IOException ioe) { ioe.printStackTrace(); }
}
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org