📄 jndisocketfactory.java
字号:
package com.ca.commons.jndi;
/**
* JndiSocketFactory.java
*
*/
import java.io.*;
import java.net.*;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.security.KeyStore;
import java.security.GeneralSecurityException;
// XXX 1.3 <-> 1.4
//import com.sun.net.ssl.*; // jdk 1.3 requires alljssl.jar in external
import javax.net.ssl.*;
import javax.naming.NamingException; // jdk 1.4 includes ssl in standard distro
/**
* <p>Socket factory for SSL jndi links that returns an SSL socket.
* It incorporates a keystore, which must contain the certs used
* to authenticate the client.</p>
*
* <p>This code is based on sample code made freely available by author
* Spencer W. Thomas on his web site http://hubris.engin.umich.edu/java/
* On Wed 24 May, 2000.</p>
*
* <p><b>Warning</b></p>
*
* <p>This class relies heavily on an internal, single, static SSLSocketFactory.
* multiple objects of this type in fact will use the same internal SSLSocketFactory.
* (This is why a single static init() method sets up everything for the entire
* class.) The reason for this structure is that JndiSocketFactory is dynmaically
* invoked by the jndi connection, and we have no other chance to initialise the
* object.</p>
*/
public class JndiSocketFactory extends SSLSocketFactory
{
/**
* This is the (static) factory internally shared between
* all JndiSocketFactory objects.
*/
private static SSLSocketFactory factory = null;
/**
* A single default object of this class. It is
* initialised when first called for, and then reused
* whenever called again.
*/
private static JndiSocketFactory default_factory = null;
private static KeyStore clientKeystore;
/**
* The sun 'JKS' keystore is the simplest and most commonly
* available keystore type.
*/
private static final String DEFAULT_KEYSTORE_TYPE = "JKS";
/**
* The 'KSE' keystore is used by the Glen Iris group to
* wrap openssl calls. It has some peculiarities requiring
* special handling.
*/
private static final String PKI_INTERNAL_TYPE = "KSE";
/**
* the class loader to use for loading security providers
* 'n stuff. Defaults to the system loader.
*/
private static ClassLoader myClassLoader = null;
/**
* Register a custom class loader to be used by
* the class when getting security providers.
*/
public static void setClassLoader(ClassLoader newLoader)
{
myClassLoader = newLoader;
}
/**
* checks that myClassLoader is initialised, uses the System
* default loader if it isn't, and returns the guaranteed
* initialised loader.
*/
private static ClassLoader getClassLoader()
{
if (myClassLoader == null)
myClassLoader = ClassLoader.getSystemClassLoader();
return myClassLoader;
}
/**
* Enable debugging...
*/
public static void setDebugOn()
{
/*
all turn on all debugging
ssl turn on ssl debugging
The following can be used with ssl:
record enable per-record tracing
handshake print each handshake message
keygen print key generation data
session print session activity
handshake debugging can be widened with:
data hex dump of each handshake message
verbose verbose handshake message printing
record debugging can be widened with:
plaintext hex dump of record plaintext
*/
System.setProperty("javax.net.debug", "ssl handshake verbose");
}
/**
* <p>Initialize the socket factory with a particular key store(s) and
* security provider. The minimum requirement is for a keystore
* containing trusted directory servers (the 'castore', or trusted
* certificate authority store, since the servers are usually signed
* by a common CA, whose cert would be held in this file).</p>
*
* <p>Further options include a private key store (the 'clientstore')
* that allows for client-authenticated ssl and SASL).</p>
*
* <p>Finally, it is possible to configure a non-standard keystore
* type and security provider. The keystore type defaults to Sun's
* JKS (at time of writting, the only keystore type that the default
* Sun security provider will handle).</p>
*
* <p>Nb. - it is possible to set a custom class loader (using
* 'registerClassLoader()' ) in which case this loader can be used
* to load the security provider.</p>
*
* @param caKeystoreFile A keystore file name of public certificates (trusted CA signs)
* @param clientKeystoreFile A keystore file name of the client's certificates, containing private keys.
* (may be null if only simple, 'server authenticated' ssl is being used).
* @param caPassphrase A password for the caKeystoreFile certificate.
* (may be null if only simple, 'server authenticated' ssl is being used, and keystore type is 'JKS').
* <b>Calling Program must manually clear passphrase after init() call.</b>
* @param clientPassphrase A password for the clientKeystoreFile certificate.
* (may be null if only simple, 'server authenticated' ssl is being used).
* <b>Calling Program must manually clear passphrase after init() call.</b>
* @param caKeystoreType The type of cakeystore file. (null => 'JKS')
* @param clientKeystoreType The type of clientkeystore file. (null => 'JKS')
*/
public static void init(String caKeystoreFile, String clientKeystoreFile,
char[] caPassphrase, char[] clientPassphrase,
String caKeystoreType, String clientKeystoreType)
throws NamingException
{
if (default_factory != null)
return;
try
{
checkFileSanity(caKeystoreFile, clientKeystoreFile, clientPassphrase);
// use the client store if there is no caKeystoreFile.
if (caKeystoreFile == null)
caKeystoreFile = clientKeystoreFile;
SSLContext sslctx;
/* XXX HERE BE DRAGONS
*
* ... attempting to make file compile and run under both 1.3 (using com.sun.net.ssl.*) and
* javax.net.ssl.* (where they moved SSLContext in v1.4). By leaving it unspecified, we
* hope that the compiler will pick up the right one at compile time. Probably means grief
* if you run a 1.3 compiled version on 1.4 or vica-versa...
*/
// XXX 1.3 <-> 1.4
// XXX This is a STOOPID Idea, since we can't set the imports at run time, so it
// shouldn't work, because it will get con-foos-ed about which version of "SSLContext" to load.
//
// TODO: could we tweak it by using fully qualified class names? Doesn't matter now I suppose,
// so much other 1.4 stuff is in the code now...
/*
if ("1.4".compareTo(System.getProperty("java.version")) >= 0)
{
sslctx = SSLContext.getInstance("TLS"); // TLS for java 1.4
}
else
{
sslctx = SSLContext.getInstance("SSLv3"); // "SSLv3" for java 1.3 ...
}
*/
// ONLY SUPPORTS Java 1.4+
// evil undocumented feature - can change SSL protocol on command line
// (needed for mainframe TOPSECRET folks who have crippled TLS implementatiuon and want to use SSLv3)
String protocol = System.getProperty("sslversion", "TLS"); // TLS for java 1.4
if (!"TLS".equals(protocol))
System.out.println("SECURITY: Using non-standard ssl version: '" + protocol + "'");
//TODO: proper logging
sslctx = SSLContext.getInstance(protocol);
/*
* The KeyManagerFactory manages the clients certificates *and* private keys,
* which allow the client to authenticate itself to others. It is not required
* for 'simple' SSL.
*/
KeyManagerFactory clientKeyManagerFactory = null;
TrustManagerFactory caTrustManagerFactory;
KeyStore caKeystore;
if ((clientPassphrase!=null) && (clientPassphrase.length>0))
{
/*
* Special hack for Glen Iris PKI group, until the pki
* keystore is fully functional.
*
* We make heavy use of reflection to allow code to
* compile and run when the com.ca.pki... libraries
* aren't available.
*/
if (PKI_INTERNAL_TYPE.equals(clientKeystoreType))
{
try
{
Class c = getClassLoader().loadClass("com.ca.commons.security.openssl.ParsePkcs12");
if (c==null)
{
System.out.println("PKI internal error");
return;
}
Constructor constructor = c.getConstructor(new Class[] {String.class, byte[].class});
// get password safely - rely on calling routine to clear clientPassphrase
int size = clientPassphrase.length;
byte[] password = new byte[size];
for (int i=0; i<size; i++)
password[i] = (byte) clientPassphrase[i];
Object pkcs12Parser = constructor.newInstance(new Object[] {clientKeystoreFile, password});
Method getSunKeyStore = c.getMethod("getSunKeyStore", new Class[] {String.class} );
clientKeystore = (KeyStore) getSunKeyStore.invoke(pkcs12Parser, new Object[] {"MyFriend"});
for (int i=0; i<size; i++) // clear temp password store.
password[i] = 0;
}
catch (Exception e)
{
System.err.println("unable to load pkcs12 parser (not in class path?)");
e.printStackTrace();
return;
}
}
else
{
/*
* Create a keystore to hold the client certificates and private keys.
*/
if (clientKeystoreType == null)
clientKeystoreType = DEFAULT_KEYSTORE_TYPE;
clientKeystore = KeyStore.getInstance(clientKeystoreType); // key manager key store
/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -