remm 2005/04/19 05:15:51 Modified: catalina/src/share/org/apache/catalina/session ManagerBase.java Log: - The syncs in getRandom got out of hand (really). - Init again the random generator inside init(). If this was a performance problem in the past, this is not anymore (and it would seem the getRandom syncs would be a bigger problem anyway). - Use APR if available to create a secure entropy value (this would likely be useful in Windows only). - Linux behavior is unchanged (it will use /dev/urandom as before). Revision Changes Path 1.43 +95 -68 jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/session/ManagerBase.java Index: ManagerBase.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/session/ManagerBase.java,v retrieving revision 1.42 retrieving revision 1.43 diff -u -r1.42 -r1.43 --- ManagerBase.java 15 Apr 2005 20:15:45 -0000 1.42 +++ ManagerBase.java 19 Apr 2005 12:15:51 -0000 1.43 @@ -24,6 +24,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.lang.reflect.Method; import java.security.AccessController; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -212,7 +213,10 @@ */ protected PropertyChangeSupport support = new PropertyChangeSupport(this); + // ------------------------------------------------------------- Security classes + + private class PrivilegedSetRandomFile implements PrivilegedAction{ public Object run(){ @@ -358,8 +362,31 @@ public String getEntropy() { // Calculate a semi-useful value if this has not been set - if (this.entropy == null) - setEntropy(this.toString()); + if (this.entropy == null) { + // Use APR to get a crypto secure entropy value + byte[] result = new byte[32]; + boolean apr = false; + try { + String methodName = "random"; + Class paramTypes[] = new Class[2]; + paramTypes[0] = result.getClass(); + paramTypes[1] = int.class; + Object paramValues[] = new Object[2]; + paramValues[0] = result; + paramValues[1] = new Integer(32); + Method method = Class.forName("org.apache.tomcat.jni.OS") + .getMethod(methodName, paramTypes); + method.invoke(null, paramValues); + apr = true; + } catch (Throwable t) { + // Ignore + } + if (apr) { + setEntropy(new String(result)); + } else { + setEntropy(this.toString()); + } + } return (this.entropy); @@ -474,29 +501,29 @@ * - so use it if available. */ public void setRandomFile( String s ) { - // as a hack, you can use a static file - and genarate the same - // session ids ( good for strange debugging ) + // as a hack, you can use a static file - and genarate the same + // session ids ( good for strange debugging ) if (System.getSecurityManager() != null){ - randomIS = (DataInputStream)AccessController.doPrivileged(new PrivilegedSetRandomFile()); - } else { - try{ - devRandomSource=s; - File f=new File( devRandomSource ); - if( ! f.exists() ) return; - randomIS= new DataInputStream( new FileInputStream(f)); - randomIS.readLong(); - if( log.isDebugEnabled() ) - log.debug( "Opening " + devRandomSource ); - } catch( IOException ex ) { - try { - randomIS.close(); - } catch (Exception e) { - log.warn("Failed to close randomIS."); - } - - randomIS=null; + randomIS = (DataInputStream)AccessController.doPrivileged(new PrivilegedSetRandomFile()); + } else { + try{ + devRandomSource=s; + File f=new File( devRandomSource ); + if( ! f.exists() ) return; + randomIS= new DataInputStream( new FileInputStream(f)); + randomIS.readLong(); + if( log.isDebugEnabled() ) + log.debug( "Opening " + devRandomSource ); + } catch( IOException ex ) { + try { + randomIS.close(); + } catch (Exception e) { + log.warn("Failed to close randomIS."); } + + randomIS=null; } + } } public String getRandomFile() { @@ -509,39 +536,35 @@ * generating session identifiers. If there is no such generator * currently defined, construct and seed a new one. */ - public synchronized Random getRandom() { + public Random getRandom() { if (this.random == null) { - synchronized (this) { - if (this.random == null) { - // Calculate the new random number generator seed - long seed = System.currentTimeMillis(); - long t1 = seed; - char entropy[] = getEntropy().toCharArray(); - for (int i = 0; i < entropy.length; i++) { - long update = ((byte) entropy[i]) << ((i % 8) * 8); - seed ^= update; - } - try { - // Construct and seed a new random number generator - Class clazz = Class.forName(randomClass); - this.random = (Random) clazz.newInstance(); - this.random.setSeed(seed); - } catch (Exception e) { - // Fall back to the simple case - log.error(sm.getString("managerBase.random", randomClass), - e); - this.random = new java.util.Random(); - this.random.setSeed(seed); - } - if(log.isDebugEnabled()) { - long t2=System.currentTimeMillis(); - if( (t2-t1) > 100 ) - log.debug(sm.getString("managerBase.seeding", randomClass) + " " + (t2-t1)); - } - } + // Calculate the new random number generator seed + long seed = System.currentTimeMillis(); + long t1 = seed; + char entropy[] = getEntropy().toCharArray(); + for (int i = 0; i < entropy.length; i++) { + long update = ((byte) entropy[i]) << ((i % 8) * 8); + seed ^= update; + } + try { + // Construct and seed a new random number generator + Class clazz = Class.forName(randomClass); + this.random = (Random) clazz.newInstance(); + this.random.setSeed(seed); + } catch (Exception e) { + // Fall back to the simple case + log.error(sm.getString("managerBase.random", randomClass), + e); + this.random = new java.util.Random(); + this.random.setSeed(seed); + } + if(log.isDebugEnabled()) { + long t2=System.currentTimeMillis(); + if( (t2-t1) > 100 ) + log.debug(sm.getString("managerBase.seeding", randomClass) + " " + (t2-t1)); } } - + return (this.random); } @@ -693,6 +716,10 @@ log.error("Error registering ",e); } } + + // Initialize random number generation + getRandomBytes(new byte[16]); + if(log.isDebugEnabled()) log.debug("Registering " + oname ); @@ -889,32 +916,32 @@ } - protected void getRandomBytes( byte bytes[] ) { + protected void getRandomBytes(byte bytes[]) { // Generate a byte array containing a session identifier - if( devRandomSource!=null && randomIS==null ) { - setRandomFile( devRandomSource ); + if (devRandomSource != null && randomIS == null) { + setRandomFile(devRandomSource); } - if(randomIS!=null ) { + if (randomIS != null) { try { - int len=randomIS.read( bytes ); - if( len==bytes.length ) { + int len = randomIS.read(bytes); + if (len == bytes.length) { return; } if(log.isDebugEnabled()) log.debug("Got " + len + " " + bytes.length ); - } catch( Exception ex ) { + } catch (Exception ex) { + // Ignore } - devRandomSource=null; - + devRandomSource = null; + try { - randomIS.close(); - } catch (Exception e) { + randomIS.close(); + } catch (Exception e) { log.warn("Failed to close randomIS."); - } - - randomIS=null; + } + + randomIS = null; } - Random random = getRandom(); getRandom().nextBytes(bytes); }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]