Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/ciphercore/Server.java


1   /* $Id: Server.java,v 1.12 2001/04/02 08:42:50 cvsbob Exp $ */
2   
3   /*
4    * Server.java, child spawning ciphercore master server.
5    * Copyright (C) 2001 Robert Bushman.
6    *
7    * I reserve the right to release this program under seperate license.
8    * If you require a special license grant contact Robert Bushman.
9    *
10   * This program is free software; you can redistribute it and/or
11   * modify it under the terms of the GNU General Public License
12   * as published by the Free Software Foundation; either version 2
13   * of the License, or (at your option) any later version.
14   *
15   * This program is distributed in the hope that it will be useful,
16   * but WITHOUT ANY WARRANTY; without even the implied warranty of
17   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18   * GNU General Public License for more details.
19   * 
20   * You should have received a copy of the GNU General Public License
21   * along with this program; if not, write to the Free Software
22   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 
23   * 02111-1307, USA.
24   */
25  
26  package com.ciphercore;
27  
28  import java.io.BufferedInputStream;
29  import java.io.DataInputStream;
30  import java.io.DataOutputStream;
31  import java.io.File;
32  import java.io.FileInputStream;
33  import java.io.FileNotFoundException;
34  import java.io.InputStream;
35  import java.io.IOException;
36  import java.io.OutputStream;
37  import java.math.BigInteger;
38  import java.net.URL;
39  import java.net.Socket;
40  import java.net.ServerSocket;
41  import java.security.AlgorithmParameters;
42  import java.security.AlgorithmParameterGenerator;
43  import java.security.InvalidAlgorithmParameterException;
44  import java.security.NoSuchAlgorithmException;
45  import java.security.Provider;
46  import java.security.Security;
47  import java.security.spec.InvalidKeySpecException;
48  import java.security.spec.InvalidParameterSpecException;
49  import java.util.HashSet;
50  import java.util.HashMap;
51  import java.util.Properties;
52  import java.util.StringTokenizer;
53  import javax.crypto.spec.DHParameterSpec;
54  import javax.crypto.interfaces.DHPublicKey;
55  import javax.crypto.interfaces.DHPrivateKey;
56  
57  import com.traxel.crypto.CipherPartner;
58  import com.traxel.crypto.CryptoUtil;
59  import com.traxel.crypto.DHUtil;
60  import com.traxel.util.ClassUtil;
61  
62  /**
63   * The CipherCore server. This is the class that responds to
64   * client requests. Each request specifies a child type, which
65   * the Server checks against it's list of allowed types. If
66   * the type is allowed, it spawns the child, gives it a copy
67   * of the servers Diffie Hellman key, and returns to waiting
68   * for the next child.
69   * <br><br>
70   * <b>Basic Usage</b><pre><tt>
71   * java com.ciphercore.Server --children=pkg1.Class1:pkg2.Class2
72   * </pre></tt>
73   */
74  public class Server {
75      
76      // ----------------------------------------------------------
77      // CONSTANTS
78      // ----------------------------------------------------------
79      
80      /** If no port is specified, run on 5943. */
81      public static final int DEFAULT_PORT = 5943;
82      public static final String DEFAULT_PROVIDER_NAME_OLD1 =
83          "com.sun.crypto.provider.SunJCE";
84      public static final String DEFAULT_PROVIDER_NAME_OLD2 =
85          "cryptix.jce.provider.CryptixCrypto";
86      public static final String DEFAULT_PROVIDER_NAME =
87          "org.bouncycastle.jce.provider.BouncyCastleProvider";    
88      // ---------------------------------------------------------
89      // CONSTRUCTORS
90      // ---------------------------------------------------------
91      
92      /**
93       * Create a Server which allows the specified children, on the
94       * default port (5943), in the specified mode
95       * (Server.SECURE_MODE or Server.INSECURE_MODE).
96       */
97      public Server( HashSet approvedChildren ) {
98          this( approvedChildren, DEFAULT_PORT );
99      }
100     
101     /**
102      * Create a Server which allows the specified children, on the
103      * specified port, in the specified mode
104      * (Server.SECURE_MODE or Server.INSECURE_MODE).
105      */
106     public Server( HashSet approvedChildren, int port ) {
107         setApprovedChildren( approvedChildren );
108         setPort( port );
109         CryptoUtil.initializeProvider( getProviderName() );
110         initializeSelf();
111     }
112     
113     private void initializeSelf() {
114         locateFiles();
115         readBasicCfg();
116         readAdvancedCfg();
117         readUserHashes();
118         readKeys();
119     }
120         
121     // ------------------------------------------------------------
122     // PUBLIC API
123     // ------------------------------------------------------------
124     
125     /**
126      * This method accepts the incoming client and hands the socket
127      * off to handleClient( socket ). In the future, this is where
128      * service independant IP based blocking (IE: across the board
129      * denial) should occur.
130      */
131     public void run() {
132         try {
133             ServerSocket serverSocket = new ServerSocket( getPort() );
134             while( true ) {
135                 System.out.println( "Server listening on " + getPort() );
136                 Socket socket = serverSocket.accept();
137                 handleClient( socket );
138             }
139         } catch( IOException e ) {
140             e.printStackTrace();
141             System.exit( 1 );
142         }
143     }
144     
145     // -----------------------------------------------------------
146     // INTERNAL API
147     // ----------------------------------------------------------
148     
149     /**
150      * This method determines the requested client type, and spawns
151      * the appropriate child. In the future, this is where
152      * service dependant IP based blocking (IE: only specific
153      * accounts can spawn childs of type X) should occur.
154      */
155     protected void handleClient( Socket socket ) throws IOException {
156         try {
157             InputStream rawIn = socket.getInputStream();
158             OutputStream rawOut = socket.getOutputStream();
159             BufferedInputStream buffIn = new BufferedInputStream( rawIn );
160             DataInputStream in = new DataInputStream( buffIn );
161             DataOutputStream out = new DataOutputStream( rawOut );
162             
163             String childClassName = readNextString( in );
164             System.out.println( "Request For Child: " + childClassName );
165             
166             launchChild( childClassName, socket );
167             
168             System.out.println( "Child Launched." );
169             
170         } catch( ClassNotFoundException e ) {
171             e.printStackTrace();
172         } catch( InstantiationException e ) {
173             e.printStackTrace();
174         } catch( IllegalAccessException e ) {
175             e.printStackTrace();
176         }
177     }
178     
179     /**
180      * A convenience method that reads the next string.
181      */
182     protected static String readNextString( DataInputStream in )
183         throws IOException {
184         
185         int     length;
186         byte[]  bytes;
187         String  string;
188         
189         length = in.readInt();
190         bytes = new byte[ length ];
191         in.readFully( bytes );
192         string = new String( bytes );
193         
194         return( string );
195     }
196     
197     /**
198      * Verifies that the specified class is allowed to run in this server,
199      * then instantiates the child, gives it a reference to this child
200      * type's interprocess object, gives it a copy of the DHPartner,
201      * and starts the child.
202      * 
203      * @param           childClassName  The name of the requested child class.
204      * @exception       ClassNotFoundException
205      * @exception       InstantiationException
206      * @exception       IllegalAccessException
207      */
208     protected Child launchChild( String childClassName, Socket socket )
209         throws ClassNotFoundException,
210                InstantiationException,
211                IllegalAccessException {
212         if( ! isApproved( childClassName ) ) {
213             throw new IllegalAccessException
214                 ( childClassName + " is not approved on this server." );
215         }
216         Class childClass = Class.forName( childClassName );
217         Child child = (Child)childClass.newInstance();
218         
219         // Hand off the current IPO
220         child.initializeInterProcessObject( getIPO( childClassName ) );
221         // In case the child new'ed the IPO, update our copy.
222         putIPO( childClassName, child.getInterProcessObject() );
223         // Give the child a duplicate of the core DHPartner
224         child.setCipherSelf
225             ( new CipherPartner( childClassName, getCipherSelf() ) );
226         // Give the child it's socket.
227         child.setSocket( socket );
228         // Let 'er rip.
229         child.start();
230         
231         return( child );
232     }
233     
234     protected void locateFiles() {
235         String byteCodePath = ClassUtil.pathToBytecode( this );
236         String configPath = null;
237         String jarLocation = "/lib/";
238         String classLocation = "/src/com/ciphercore/Server.class";
239         if( byteCodePath.indexOf( ".jar" ) > -1 ) {
240             configPath = byteCodePath.substring
241                 ( 5, byteCodePath.lastIndexOf( jarLocation ) );
242         } else {
243             configPath = byteCodePath.substring
244                 ( 5, byteCodePath.lastIndexOf( classLocation ) );
245         }
246         configPath = configPath + "/config/server";
247         
248         setBasicCfgLocation( configPath + "/basic.cfg" );
249         setAdvancedCfgLocation( configPath + "/advanced.cfg" );
250         setPubKeyLocation( configPath + "/public.key" );
251         setPubSha1Location( configPath + "/public.sha1" );
252         setPrivKeyLocation( configPath + "/private.key" );
253         setUserHashesLocation( configPath + "/user.hashes" );
254     }
255     
256     protected void readBasicCfg() {
257         FileInputStream fileIn;
258         Properties properties;
259         
260         properties = new Properties();
261         try {
262             fileIn = new FileInputStream( getBasicCfgLocation() );
263             properties.load( fileIn );
264         } catch( Exception e ) {
265             e.printStackTrace();
266             System.err.println( "Failed to access basic config file." );
267             System.err.println( "  Location: " + getBasicCfgLocation() );
268             System.exit( 1 );
269         }
270     }
271     
272     protected void readAdvancedCfg() {
273         FileInputStream fileIn;
274         Properties properties;
275         
276         properties = new Properties();
277         try {
278             fileIn = new FileInputStream( getAdvancedCfgLocation() );
279             properties.load( fileIn );
280         } catch( Exception e ) {
281             e.printStackTrace();
282             System.err.println( "Failed to access advanced config file." );
283             System.err.println( "  Location: " + getAdvancedCfgLocation() );
284             System.exit( 1 );
285         }
286     }
287     
288     protected void readUserHashes() {
289         FileInputStream fileIn;
290         Properties userHashes;
291         
292         userHashes = new Properties();
293         try {
294             fileIn = new FileInputStream( getUserHashesLocation() );
295             userHashes.load( fileIn );
296         } catch( Exception e ) {
297             e.printStackTrace();
298             System.err.println( "Failed to access user hashes file." );
299             System.err.println( "  Location: " + getUserHashesLocation() );
300             System.exit( 1 );
301         }
302         setUserHashes( userHashes );
303     }
304     
305     protected void readKeys() {
306         FileInputStream pubIn;
307         FileInputStream privIn;
308         File sha1File;
309         DHPublicKey pubKey;
310         DHPrivateKey privKey;
311         CipherPartner self;
312         String keyLocations =
313             "  " + getPubKeyLocation() + "\n"
314             + "  " + getPrivKeyLocation() + "\n"
315             + "  " + getPubSha1Location();
316         
317         try {
318             self = new CipherPartner( "SERVER",
319                                       getPubKeyLocation(),
320                                       getPrivKeyLocation() );
321             setCipherSelf( self );
322         } catch( FileNotFoundException e ) {
323             System.out.println();
324             e.printStackTrace();
325             System.out.println
326                 ( "WARNING: One or more of the key files not found." );
327             System.out.println( keyLocations );
328             generateKeys();
329             System.exit( 1 );
330         } catch( InvalidKeySpecException e ) {
331             System.out.println();
332             e.printStackTrace();
333             System.out.println( "One or more of the key files is corrupt." );
334             System.out.println( keyLocations );
335             System.out.println( "Deleting the files will force regeneration." );
336             System.exit( 1 );
337         } catch( IOException e ) {
338             System.out.println();
339             e.printStackTrace();
340             System.out.println
341                 ( "WARNING: One or more of the key files could not be read." );
342             System.out.println( keyLocations );
343             System.exit( 1 );
344         } catch( Exception e ) {
345             System.out.println();
346             e.printStackTrace();
347             System.out.println
348                 ( "WARNING: Diffie Hellman key file error." );
349             System.out.println( keyLocations );
350             System.exit( 1 );
351         }
352     }
353     
354     protected void generateKeys() {
355         CipherPartner self;
356         
357         System.out.println( "Beginning Diffie Hellman key generation." );
358         
359         try {
360             self = new CipherPartner( "SERVER", getParams() );
361             self.exportDhKeys( getPubKeyLocation(),
362                                getPrivKeyLocation(),
363                                getPubSha1Location() );
364         } catch( Exception e ) {
365             System.out.println();
366             System.out.println( "Failed to write Diffie Hellman key files." );
367             System.out.println( "  " + getPubKeyLocation() + "\n"
368                                 + "  " + getPrivKeyLocation() + "\n"
369                                 + "  " + getPubSha1Location() );
370             System.out.println( "ALERT: Make sure the config directory "
371                                 + "exists and is writeable." );
372             System.exit( 1 );
373         }
374         
375         System.out.println();
376         System.out.println( "You can now secure the file "
377                             + getPrivKeyLocation() + " if you wish." );
378         System.out.println( "NOTE: It must be readable by this process." );
379         System.out.println( "When you're ready, restart the server." );
380         System.exit( 1 );
381     }
382     
383     // --------------------------------------------------------
384     // INSTANCE PARAMETERS AND ACCESSORS
385     // --------------------------------------------------------
386     
387     // PARAMETERS
388     private int _port = DEFAULT_PORT;
389     private DHParameterSpec _params = DHStock.PARAMS;
390     private CipherPartner _cipherSelf;
391     private HashMap _interProcessObjects = new HashMap();
392     private HashSet _approvedChildren;
393     private String _basicCfgLocation;
394     private String _advancedCfgLocation;
395     private String _pubKeyLocation;
396     private String _pubSha1Location;
397     private String _privKeyLocation;
398     private String _userHashesLocation;
399     private Properties _userHashes;
400     
401     // SETTERS
402     protected void setPort( int port ) { _port = port; }
403     protected void setParams( DHParameterSpec params ) { _params = params; }
404     protected void setCipherSelf( CipherPartner self ) { _cipherSelf = self; }
405     protected void putIPO( String childClassName, InterProcessObject ipo ) {
406         _interProcessObjects.put( childClassName, ipo );
407     }
408     protected void setBasicCfgLocation( String location ) {
409         _basicCfgLocation = location;
410     }
411     protected void setAdvancedCfgLocation( String location ) {
412         _advancedCfgLocation = location;
413     }
414     protected void setPubKeyLocation( String location ) {
415         _pubKeyLocation = location;
416     }
417     protected void setPubSha1Location( String location ) {
418         _pubSha1Location = location;
419     }
420     protected void setPrivKeyLocation( String location ) {
421         _privKeyLocation = location;
422     }
423     protected void setUserHashesLocation( String location ) {
424         _userHashesLocation = location;
425     }
426     protected void setUserHashes( Properties userHashes ) {
427         _userHashes = userHashes;
428     }
429     
430     protected void setApprovedChildren( HashSet approvedChildren ) {
431         _approvedChildren = approvedChildren;
432     }
433     
434     // GETTERS
435     public int getPort() { return( _port ); }
436     public DHParameterSpec getParams() { return( _params ); }
437     public CipherPartner getCipherSelf() { return( _cipherSelf ); }
438     public boolean isApproved( String childClassName ) {
439         return( _approvedChildren.contains( childClassName ) );
440     }
441     public String getProviderName() { return( DEFAULT_PROVIDER_NAME ); }
442     public String getBasicCfgLocation() { return( _basicCfgLocation ); }
443     public String getAdvancedCfgLocation() { return( _advancedCfgLocation ); }
444     public String getPubKeyLocation() { return( _pubKeyLocation ); }
445     public String getPubSha1Location() { return( _pubSha1Location ); }
446     public String getPrivKeyLocation() { return( _privKeyLocation ); }
447     public String getUserHashesLocation() { return( _userHashesLocation ); }
448     public Properties getUserHashes() { return( _userHashes ); }
449     
450     public InterProcessObject getIPO( String childClassName ) {
451         return( (InterProcessObject)_interProcessObjects.get(childClassName) );
452     }
453     
454     // CONVENIENCE METHODS
455     public String getUserHash( String userName ) {
456         return( (String)getUserHashes().get( userName ) );
457     }
458     
459     // ------------------------------------------------------
460     // RUNTIME
461     // ------------------------------------------------------
462     
463     protected static HashSet parseApprovedChildren( String[] args ) {
464         boolean childrenSpecified = false;
465         HashSet approvedChildren = new HashSet();
466         if( args != null ) {
467             for( int i = 0; i < args.length; i++ ) {
468                 if( args[i].indexOf( "--children=" ) == 0 ) {
469                     String children = args[i].substring( 11 );
470                     StringTokenizer toker = new StringTokenizer( children, ":" );
471                     while( toker.hasMoreTokens() ) {
472                         approvedChildren.add( toker.nextToken() );
473                     }
474                     childrenSpecified = true;
475                 }
476             }
477         }
478         if( ! childrenSpecified ) {
479             approvedChildren = new HashSet();
480             approvedChildren.add( "com.ciphercore.samples.ChildDemo" );
481         }
482         return( approvedChildren );
483     }
484     
485     public static void main( String[] args ) throws IOException {
486         Server server;
487         HashSet approvedChildren = parseApprovedChildren( args );
488         
489         server = new Server( approvedChildren );
490         
491         server.run();
492     }
493 }
494