not-yet-commons-ssl



RMI over SSL (experimental)


3 points to consider:
  1. To run the RMI-SSL server, you must invoke LocateRegistry.createRegistry( 1099 ) from within your own application. You must do this AFTER calling RMISocketFactory.setSocketFactory( impl ). RMISocketFactoryImpl will open the registry on 1099, and will open anonymous RMI servers (where port 0 is specified) on port 31099. RMI-SSL, as shown here, doesn't work with $JAVA_HOME/bin/rmiregistry.
    See the example code below for help with RMISocketFactory.setSocketFactory( impl ).
  2. To run the RMI-SSL client, you need to find an RMI-SSL server to connect to. See #1, above.  ;-)
  3. If you don't manage to find an RMI-SSL server, then the RMI-SSL client will automatically downgrade itself to plain-socket. There is an important security consideration to consider regarding this: RMISocketFactoryImpl at this time only guarantees the security of the registry and the server sockets it opens. Client sockets it creates might be plain-socket.
RMI over SSL Example

import org.apache.commons.ssl.RMISocketFactoryImpl;

// RMISocketFactoryImpl tries to detect plain sockets, so you should be able to use
// this even in situations where not all of the RMI servers you are talking to are
// using SSL.
RMISocketFactoryImpl impl = new RMISocketFactoryImpl();

// Let's change some settings on our default SSL client.
SSLClient defaultClient = (SSLClient) impl.getDefaultClient();
client.setCheckHostname( false );
client.setCheckCRL( true );
client.setCheckExpiry( false );

// By default we trust Java's "cacerts", as well as whatever cert is on localhost:1099,
// so this is redundant:   (Trusting localhost:1099 is some commons-ssl magic).
client.addTrustMaterial( TrustMaterial.DEFAULT );

// But if we had used setTrustMaterial() instead of addTrustMaterial(), we would (probably)
// no longer trust localhost:1099!  Using set instead of add causes all previous "adds" to
// to be thrown out.

// Meanwhile, RMI calls to rmi://special.com:1099/ need to trust a self-signed certificate,
// but we don't want to pollute our default trust with this shoddy cert.  So only calls
// specifically to "special.com" (any port) will use this.
SSLClient specialClient = new SSLClient();
TrustMaterial tm = new TrustMaterial( "special.pem" );
specialClient.addTrustMaterial( tm );
// Here's where the special cert gets associated with "special.com":
impl.setClient( "special.com", specialClient );


// We're might also want to be an RMI server ourselves!
// By default commons-ssl looks for "~/.keystore" and tries password "changeit",
// but we can change things if we want:
SSLServer server = (SSLServer) impl.getDefaultServer();
tm = new TrustMaterial( "trust_only_these_client_certs.pem" );
KeyMaterial km = new KeyMaterial( "/path/to/myKey.p12", "password".toCharArray() );
server.setTrustMaterial( tm );
server.setKeyMaterial( km );
// This particular RMI server will only accept connections with client certs!
server.setNeedClientAuth( true );

// Finally, we tell Java to use our new RMI socket factory!
RMISocketFactory.setSocketFactory( impl );