SDSU CS 696 Emerging Technologies: Distributed Objects
Spring Semester, 1998
RMI Security

To Lecture Notes Index
© 1998, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 21-Apr-98

Contents of Doc 12, RMI Security

  1. References
  2. Security
  3. RMI and Security
    1. Creating a Custom Socket
    2. Creating a Custom RMISocketFactory
    3. Using the RMISocketFactory
  4. RMI & JDK1.2
    1. Specifying Socket Type per Object
      1. Server Using Specifying Own Socket
      2. Client

References


CS596 Client Server Lecture notes, Security, Spring 1997, htp://www.eli.sdsu.edu/courses/spring97/cs596/notes/security/security.html

Creatinga Custom Socket Type, http://www.sdsu.edu/doc/jdk1.2/docs/guide/rmi/sockettype.doc.html

Ceating a Custom RMISocketFactory, http://www.sdsu.edu/doc/jdk1.2/docs/guide/rmi/rmisocketfactory.doc.html

The following notes contain information taken nearly verbatim from the above sources. However, there are some small, but important changes made at times.

Doc 12, RMI Security Slide # 2

Security

What to secure

Before we can talk about security related to computers and networks, we need to know what we are trying to secure:
Restricted data
Computer access (resources)
Algorithms
Etc.

Doc 12, RMI Security Slide # 3
Types of security

Some different types:
Physical security:

Prevent access to physical devices (network, computers, etc.) with:
locks and keys
security guard
guard dogs
alarm system
etc.
Software security:

Authentication
Encryption
Audit trail
Etc.

Doc 12, RMI Security Slide # 4
Types of attacks

Some common methods of "attacks":
Impersonation
Sniffing
Replay
Denial of service

Doc 12, RMI Security Slide # 5
Authentication

Authentication is performed to ensure that a user or program has specific access to a resource or data.

Examples:
Unix login procedure
SDSU modem pool login
ATM card and PIN
Finger printing
"Smart" card
etc.

The authentication process normally relies on some sort of shared (between resource provider and resource seeker) secret or irreproducible
attribute:
Password
Retinal image
Finger print
Algorithm and key in "Smart" card
Physical location (IP address)


Doc 12, RMI Security Slide # 6
Network Authentication

How is authentication over a network different?

Network packets can travel through many "unknown" (read untrusted) routers and computers.

What are the added risks?
Network sniffing
Traffic logging
Etc.

Some issues:
Passwords, data can be "sniffed" from the network
Traffic patterns can be analyzed




Doc 12, RMI Security Slide # 7

RMI and Security


Java provides security manager to provide controls over what client or server can do a machine

Your application needs to insure proper security manager in installed in application

java.securtiy package is useful in encryption, etc.

Other types of security are your application's problem

RMI addresses encrypting of data over the wire
RMI Wire encryption Process

1. Create a custom socket type that does encryption

2. Create and install a socket factory in you RMI application

We will use xor encryption
exclusive or all bytes in a stream by a mask byte
the byte stream is hard to read by untrained users
exclusive or all bytes a second time by the same mask byte to get original byte stream


Doc 12, RMI Security Slide # 8

Creating a Custom Socket


1. Subclass FilterOutputStream and FilterInputStream to create streams to be used in the socket

2. Subclass java.net.Socket

3. Subclass java.net.ServerSocket


Doc 12, RMI Security Slide # 9
XorInputStream
public class XorInputStream extends FilterInputStream
   {
   byte codeMask = 0;
   
      public XorInputStream(InputStream in, byte mask) 
      {
      super(in);
      codeMask = mask;
      }

   public int read() throws IOException 
      {
      int input = in.read();
      if ( input < 0 )
         return input;
      else
         return (byte) input ^ codeMask;
      }

   public int read(byte inputBuffer[], int offset, int length) 
      throws IOException 
      {
      byte[] codedInput = new byte[length];
      int bytesRead = in.read( codedInput );
      
      for (int k = 0; k < bytesRead;k++)
         inputBuffer[offset + k ] = (byte) 
                              (codedInput[k] ^ codeMask);
      return bytesRead;
      }
   }

Doc 12, RMI Security Slide # 10
XorOutputStream
public class XorOutputStream extends FilterOutputStream
   {
   byte codeMask = 0;
   
   public XorOutputStream(OutputStream out, byte mask) 
      {
      super(out);
      codeMask = mask;
      }

   public void write(int output) throws IOException 
      {
      if ( output < 0 ) //not a byte, 
         {
         out.write(output);
         }
      else
         out.write( ((byte) output) ^ codeMask );
      }

   public void write(byte output[], int offset, int length) 
      throws IOException 
      {
      byte[] coded = new byte[length];
      for (int i = 0 ; i < length ; i++) 
         {
         coded[i] = (byte) ( output[offset + i] ^ (byte) codeMask );
         }
      out.write( coded);
      }
   }

Doc 12, RMI Security Slide # 11
XorSocket
public class XorSocket extends java.net.Socket 
   {

   /* Streams used by socket */
   private InputStream in;
   private OutputStream out;

   private byte xorMask = 0;

   public XorSocket( byte mask) // This is needed!!
      throws IOException 
      {
      super();
      xorMask = mask;
      }

   public XorSocket(String host, int port, byte mask) 
      throws IOException 
      {
      super(host, port);
      xorMask = mask;
      }


Doc 12, RMI Security Slide # 12
XorSocket - Continued


   public InputStream getInputStream() 
      throws IOException 
      {
      if (in == null) 
         {
         BufferedInputStream buffered = 
            new BufferedInputStream( super.getInputStream() );
         in = new XorInputStream( buffered , xorMask);
         }
      return in;
      }

   public OutputStream getOutputStream() 
      throws IOException 
      {
      if (out == null) 
         {
         BufferedOutputStream buffered = 
            new BufferedOutputStream( super.getOutputStream() );
         out = new XorOutputStream(buffered, xorMask);
         }
      return out;
      }

   public synchronized void close() throws IOException 
      {
      OutputStream out = getOutputStream();
      out.flush();
      super.close();
      }
   }

Doc 12, RMI Security Slide # 13
XorServerSocket
public class XorServerSocket extends ServerSocket 
   {

   private byte xorMask = 0;
   
   public XorServerSocket(int port, byte mask) 
      throws IOException 
      {
      super(port);
      xorMask = mask;
      }

   public XorServerSocket(int port, int backlog, byte mask) 
      throws IOException 
      {
      super(port, backlog);
      xorMask = mask;
      }

   public XorServerSocket(int port, 
                           int backlog,  
                           InetAddress bindAddress, 
                           byte mask) 
      throws IOException 
      {
      super(port, backlog, bindAddress);
      xorMask = mask;
      }

   public Socket accept() throws IOException 
      {
      Socket socket = new XorSocket( xorMask );
      implAccept(socket);
      return socket;
      }
   }

Note ServerSocket uses the Strategy and Prototype patterns

Doc 12, RMI Security Slide # 14

Creating a Custom RMISocketFactory

public class XorRMISocketFactory extends RMISocketFactory 
   {

   private byte xorMask = 0;
   
   public XorRMISocketFactory( byte mask )
      {
      xorMask = mask;
      }
      
   public Socket createSocket(String host, int port)
      throws IOException
      {
      XorSocket socket = 
         new XorSocket(host, port, xorMask);
      return socket;
      }

   public ServerSocket createServerSocket(int port)
       throws IOException
      {
      XorServerSocket server = 
          new XorServerSocket(port, xorMask);
      return server;
      }
   }

Doc 12, RMI Security Slide # 15

Using the RMISocketFactory

Interface
public interface Hello extends java.rmi.Remote 
   {
   String sayHello() throws java.rmi.RemoteException;
   }

Client
public class HelloClient 
   {
   public static void main(String args[]) 
      {
      try 
         {
         String server = getHelloHostAddress( args);

         Hello remote = (Hello) Naming.lookup( server );
         RMISocketFactory.setSocketFactory(
               new XorRMISocketFactory( (byte) 0x1A ) );
         String message = remote.sayHello();
         System.out.println( message );
         } 
      catch ( Exception error) 
         {
         error.printStackTrace();
         }
      }
   private static String getHelloHostAddress( String args[] ) throws IOException
      {
      ProgramProperties flags = new ProgramProperties( args );
      String host = flags.getString( "host" );
      String port = flags.getString( "port", "1099" );
      return "rmi://" + host + ":" + port + "/HelloServer";
      }
   }


Doc 12, RMI Security Slide # 16
Server

public class HelloServer 
      extends UnicastRemoteObject
      implements Hello
   {
   public HelloServer() throws RemoteException {}

   public String sayHello() throws RemoteException 
      { return  "Hello World from someWhere" ;}

   public static void main(String args[])
      {
      // Create and install a security manager
      System.setSecurityManager(new RMISecurityManager());

      try 
         {
         String serverAddress = getHelloHostAddress( args );

         HelloServer serverObject = new HelloServer();
         
         Naming.rebind( serverAddress, serverObject);
         RMISocketFactory.setSocketFactory(
            new XorRMISocketFactory( (byte) 0x1A ) );
      
         System.out.println("HelloServer bound in registry");
         } 
      catch (Exception e) 
         {
         System.out.println("HelloServer err: " + e);
         }
      }
   }


Doc 12, RMI Security Slide # 17
Warning

The RMI Registry uses normal sockets

You must perform all interaction with the Registry before you set the socket factory

You can only set the factory once!

Doc 12, RMI Security Slide # 18

RMI & JDK1.2

Specifying Socket Type per Object


The following example does not work in jdk1.1.x
You must use jdk1.2b2 or later to run this example
package whitney.rmi.examples.basic;

import java.io.*;
import java.net.*;
import java.rmi.*;
import java.rmi.server.*;
import sdsu.net.*;

public class MultiRMISocketFactory extends RMISocketFactory 
   {
   
    /* Get the default RMISocketFactory */
    private RMISocketFactory defaultFactory 
          = RMISocketFactory.getDefaultSocketFactory();

   /* 
    * Override createSocket to call the default 
    * RMISocketFactory's createSocket method. This
    * way, you'll get a TCP connection if you don't
    * specify another SocketType
    */
   public Socket createSocket(String host, int port) 
       throws IOException 
      {
       return defaultFactory.createSocket(host, port);
      }


Doc 12, RMI Security Slide # 19
//MultiRMISocketFactory Continued
   /* 
    * Override createServerSocket to call the default
    * RMISocketFactory's createServerSocket method.
    */
   public ServerSocket createServerSocket(int port) 
   throws IOException 
      {
      return defaultFactory.createServerSocket(port);
      }

   /*
    * Override createSocket to create the type of socket 
    * specified by the SocketType parameter.
    */
   public Socket createSocket(String host, int port, 
                              SocketType type)
   throws IOException
      {
      Socket socket;
      String protocol = type.getProtocol();
      if(protocol.equals("xor"))
         { 
         byte[] xorMask = type.getRefData();
         socket = new XorSocket(host, port, xorMask[0]);
         }
      else 
         throw new IOException("protocol " + protocol + 
         " not supported");

      return socket;
      }


Doc 12, RMI Security Slide # 20
//MultiRMISocketFactory Continued

   /*
    * Override createServerSocket to create the type of socket
    * specified by the SocketType parameter.
    */
   public ServerSocket createServerSocket(int port, 
                                 SocketType type)
   throws IOException
      {
      ServerSocket server;
      String protocol = type.getProtocol();
      if(protocol.equals("xor"))
         { 
         Byte xorMask = (Byte) type.getServerData();
         server = new XorServerSocket(port,  
                              xorMask.byteValue());
         }
      else 
            throw new IOException("protocol " + protocol + 
            " not supported");

      return server;
      }
}

Doc 12, RMI Security Slide # 21
SocketType - New in JDK 1.2
Constructor
SocketType(String protocol,
byte[] clientData, Object serverData)

Methods
equals(Object)
Compares two Objects for equality.
getProtocol()
Return the protocol string for this descriptor.
getRefData()
Return the optional client data for this descriptor.
getServerData()
Return the server-specific data for this descriptor.
hashCode()
Returns a hash code value for the object.
read(DataInput)
Read a descriptor from input stream.
toString()
Returns a string representation of the object.
write(DataOutput)
Write descriptor to output stream.

Doc 12, RMI Security Slide # 22

Server Using Specifying Own Socket

package whitney.rmi.examples.basic;

import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.rmi.server.*;
import sdsu.util.ProgramProperties;
import sdsu.rmi.server.*;

public class HelloServer 
      extends UnicastRemoteObject
      implements Hello
   {

   public HelloServer() throws RemoteException 
      {
      super(0, getSocketType() ); 
      }

   private static SocketType getSocketType()
      {
      String protocol = "xor";
      byte[] forClientSide = { (byte)0xAA };
      Byte forServerSide = new Byte( (byte)0xAA );

      return new SocketType( protocol, 
                              forClientSide, 
                              forServerSide);
      }

   public String sayHello() throws RemoteException 
      {
      return  "Hello World from " + getUnixHostName();
      }

   protected static String getUnixHostName()
      {
      try
         {
         Process hostName = Runtime.getRuntime().exec( "hostname" );
         BufferedReader answer = new BufferedReader( 
               new InputStreamReader( hostName.getInputStream()) );
         hostName.waitFor();
         return answer.readLine().trim();
         }
      catch (Exception noName)
         {
         return "Nameless";
         }
      }

   private static String getHelloHostAddress( String args[] ) throws IOException
      {
      ProgramProperties flags = new ProgramProperties( args );
      String port = flags.getString( "port", "1099" );

      String host = flags.getString( "host", getUnixHostName());
      
      return  "rmi://" + ":" + port + "/HelloServer";
      }
      

Doc 12, RMI Security Slide # 23
//Server Continued

   public static void main(String args[])
      {
      // Create and install a security manager
      System.setSecurityManager(new RMISecurityManager());

      try 
         {
         String serverAddress = getHelloHostAddress( args );
         RMISocketFactory.setSocketFactory(
            new MultiRMISocketFactory( ) );

         HelloServer serverObject = new HelloServer();
         
         Naming.rebind( serverAddress, serverObject);
      
         System.out.println("HelloServer bound in registry");
         } 
      catch (Exception e) 
         {
         System.out.println("HelloServer err: ");
         e.printStackTrace();
         }
      }
   }


Doc 12, RMI Security Slide # 24

Client

package whitney.rmi.examples.basic;

import java.rmi.*;
import java.net.MalformedURLException;
import java.io.IOException;
import java.rmi.server.*;
import sdsu.util.ProgramProperties;
import sdsu.rmi.server.*;

public class HelloClient 
   {
   public static void main(String args[]) 
      {
      try 
         {
         // Set before contacting Registry!!
         RMISocketFactory.setSocketFactory(
               new MultiRMISocketFactory( )
               );

         String server = getHelloHostAddress( args);

         Hello remote = (Hello) Naming.lookup( server );
         String message = remote.sayHello();
         System.out.println( message );
         } 
      catch ( Exception error) 
         {
         error.printStackTrace();
         }
      }

   private static String getHelloHostAddress( String args[] ) throws IOException
      {
      ProgramProperties flags = new ProgramProperties( args );
      String host = flags.getString( "host" );
      String port = flags.getString( "port", "1099" );
      
      return "rmi://" + host + ":" + port + "/HelloServer";
      }
   }




visitors since 19-Feb-98