This fix from Mario should fix this security issue by changing
the PRNGs in the crypto classes to use the VMSecureRandom support.

ChangeLog:

2009-01-22  Mario Torre  <neug...@aicas.com>

        PR classpath/38417:
        * gnu/java/security/jce/prng/SecureRandomAdapter.java:
        (getSeed(int)): New; retrieve seed from source specified
        by securerandom.source property or failing that, use
        VMSecureRandom.
        * gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java:
        (engineGenerateSeed(int)): Use SecureRandomAdapter.
        (engineNextBytes(byte[])): Initialise using new seed.
        * gnu/javax/crypto/jce/prng/CSPRNGSpi.java:
        (engineGenerateSeed(int)): Use SecureRandomAdapter.
        (engineNextBytes(byte[])): Initialise using new seed.
        * gnu/javax/crypto/jce/prng/FortunaImpl.java:
        (engineSetSeed(byte[])): Initialise with new seed if unused.
        (engineGenerateSeed(int)): Use SecureRandomAdapter.     
        * gnu/javax/crypto/jce/prng/ICMRandomSpi.java:
        (engineGenerateSeed(int)): Use SecureRandomAdapter.     
        (engineNextBytes(byte[])): Initialise using new seed.
        * gnu/javax/crypto/jce/prng/UMacRandomSpi.java:
        (engineGenerateSeed(int)): Use SecureRandomAdapter.     
        (engineNextBytes(byte[])): Initialise using new seed.
        * gnu/javax/crypto/prng/ICMGenerator.java:
        (setup(Map)): Call fillBlock().

-- 
Andrew :)

Support Free Java!
Contribute to GNU Classpath and the OpenJDK
http://www.gnu.org/software/classpath
http://openjdk.java.net
PGP Key: 94EFD9D8 (http://subkeys.pgp.net)
Fingerprint = F8EF F1EA 401E 2E60 15FA  7927 142C 2591 94EF D9D8
Index: gnu/java/security/jce/prng/SecureRandomAdapter.java
===================================================================
RCS file: 
/sources/classpath/classpath/gnu/java/security/jce/prng/SecureRandomAdapter.java,v
retrieving revision 1.3
diff -u -u -r1.3 SecureRandomAdapter.java
--- gnu/java/security/jce/prng/SecureRandomAdapter.java 19 Jun 2006 12:43:48 
-0000      1.3
+++ gnu/java/security/jce/prng/SecureRandomAdapter.java 3 Feb 2009 20:45:10 
-0000
@@ -38,35 +38,58 @@
 
 package gnu.java.security.jce.prng;
 
+import gnu.java.security.action.GetSecurityPropertyAction;
+import gnu.classpath.SystemProperties;
 import gnu.java.security.prng.LimitReachedException;
 import gnu.java.security.prng.MDGenerator;
 
+import java.security.AccessController;
+import java.security.SecureRandom;
+import java.security.VMSecureRandom;
 import java.security.SecureRandomSpi;
+
 import java.util.Collections;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+import java.net.MalformedURLException;
+import java.net.URL;
 
 /**
- * The implementation of a generic {...@link java.security.SecureRandom} 
adapter
- * class to wrap GNU PRNG instances based on Message Digest algorithms.
- * <p>
- * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) for
+ * <p>The implementation of a generic {...@link java.security.SecureRandom} 
adapter
+ * class to wrap gnu.crypto prng instances based on Message Digest 
algorithms.</p>
+ *
+ * <p>This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) for
  * the {...@link java.security.SecureRandom} class, which provides the
- * functionality of a cryptographically strong pseudo-random number generator.
- * <p>
- * All the abstract methods in the {...@link SecureRandomSpi} class are 
implemented
- * by this class and all its sub-classes.
+ * functionality of a cryptographically strong pseudo-random number 
generator.</p>
+ *
+ * <p>All the abstract methods in the {...@link SecureRandomSpi} class are
+ * implemented by this class and all its sub-classes.</p>
  */
-abstract class SecureRandomAdapter
-    extends SecureRandomSpi
+public abstract class SecureRandomAdapter 
+  extends SecureRandomSpi
 {
+
+  private boolean isSeeded = false;
+
   /** Our underlying prng instance. */
   private MDGenerator adaptee = new MDGenerator();
 
   /** The name of the message digest algorithm used by the adaptee. */
   private String mdName;
 
+  private static final Logger logger =
+    Logger.getLogger(SecureRandom.class.getName());
+
+  private static final String SECURERANDOM_SOURCE = "securerandom.source";
+  private static final String JAVA_SECURITY_EGD = "java.security.egd";
+
   /**
-   * Trivial protected constructor.
-   * 
+   * <p>Trivial protected constructor.</p>
+   *
    * @param mdName the canonical name of the underlying hash algorithm.
    */
   protected SecureRandomAdapter(String mdName)
@@ -74,23 +97,77 @@
     super();
 
     this.mdName = mdName;
-    adaptee.init(Collections.singletonMap(MDGenerator.MD_NAME, mdName));
+    adaptee.init (Collections.singletonMap (MDGenerator.MD_NAME, mdName));
   }
 
-  public byte[] engineGenerateSeed(int numBytes)
+  public static final byte[] getSeed(int numBytes)
   {
-    if (numBytes < 1)
-      return new byte[0];
+    URL sourceUrl = null;
+    String urlStr = null;
+
+    byte[] buffer = new byte[numBytes];
 
-    byte[] result = new byte[numBytes];
-    this.engineNextBytes(result);
-    return result;
+    GetSecurityPropertyAction action =
+      new GetSecurityPropertyAction(SECURERANDOM_SOURCE);
+    try
+      {
+        urlStr = (String) AccessController.doPrivileged(action);
+        if (urlStr != null)
+          sourceUrl = new URL(urlStr);
+      }
+    catch (MalformedURLException ignored)
+      {
+        logger.log(Level.WARNING,
+                  SECURERANDOM_SOURCE + " property is malformed: {0}", 
+                   urlStr);
+      }
+
+    if (sourceUrl == null)
+      {
+        try
+          {
+            urlStr = SystemProperties.getProperty(JAVA_SECURITY_EGD);
+            if (urlStr != null)
+              sourceUrl = new URL(urlStr);
+          }
+        catch (MalformedURLException mue)
+          {
+            logger.log(Level.WARNING,
+                      JAVA_SECURITY_EGD + " property is malformed: {0}",
+                       urlStr);
+          }
+      }
+
+    if (sourceUrl != null)
+      {
+        try
+          {
+            InputStream in = sourceUrl.openStream();
+            in.read(buffer);
+            return buffer;
+          }
+        catch (IOException ioe)
+          {
+            logger.log(Level.FINE, "error reading random bytes", ioe);
+          }
+      }
+
+    // If we get here, we did not get any seed from a property URL.
+    VMSecureRandom.generateSeed(buffer, 0, buffer.length);
+    return buffer;
+  }
+
+  public byte[] engineGenerateSeed(int numBytes)
+  {
+    return getSeed(numBytes);
   }
 
   public void engineNextBytes(byte[] bytes)
   {
-    if (! adaptee.isInitialised())
-      this.engineSetSeed(new byte[0]);
+    if (!isSeeded)
+      {
+        engineSetSeed(engineGenerateSeed(32));
+      }
     try
       {
         adaptee.nextBytes(bytes, 0, bytes.length);
@@ -102,6 +179,7 @@
 
   public void engineSetSeed(byte[] seed)
   {
-    adaptee.addRandomBytes(seed);
+    adaptee.addRandomBytes (seed);
+    isSeeded = true;
   }
 }
Index: gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java
===================================================================
RCS file: 
/sources/classpath/classpath/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java,v
retrieving revision 1.2
diff -u -u -r1.2 ARCFourRandomSpi.java
--- gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java     26 Jun 2006 13:30:14 
-0000      1.2
+++ gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java     3 Feb 2009 20:45:11 
-0000
@@ -39,12 +39,17 @@
 package gnu.javax.crypto.jce.prng;
 
 import gnu.java.security.Registry;
-import gnu.javax.crypto.prng.ARCFour;
+
+import gnu.java.security.jce.prng.SecureRandomAdapter;
+
 import gnu.java.security.prng.IRandom;
 import gnu.java.security.prng.LimitReachedException;
+
+import gnu.javax.crypto.prng.ARCFour;
 import gnu.javax.crypto.prng.PRNGFactory;
 
 import java.security.SecureRandomSpi;
+
 import java.util.HashMap;
 
 /**
@@ -71,17 +76,13 @@
 
   public byte[] engineGenerateSeed(int numBytes)
   {
-    if (numBytes < 1)
-      return new byte[0];
-    byte[] result = new byte[numBytes];
-    this.engineNextBytes(result);
-    return result;
+    return SecureRandomAdapter.getSeed(numBytes);
   }
 
   public void engineNextBytes(byte[] bytes)
   {
     if (virgin)
-      this.engineSetSeed(new byte[0]);
+      this.engineSetSeed(engineGenerateSeed(32));
     try
       {
         adaptee.nextBytes(bytes, 0, bytes.length);
Index: gnu/javax/crypto/jce/prng/CSPRNGSpi.java
===================================================================
RCS file: 
/sources/classpath/classpath/gnu/javax/crypto/jce/prng/CSPRNGSpi.java,v
retrieving revision 1.3
diff -u -u -r1.3 CSPRNGSpi.java
--- gnu/javax/crypto/jce/prng/CSPRNGSpi.java    26 Jun 2006 13:30:14 -0000      
1.3
+++ gnu/javax/crypto/jce/prng/CSPRNGSpi.java    3 Feb 2009 20:45:11 -0000
@@ -40,6 +40,7 @@
 
 import gnu.java.security.prng.IRandom;
 import gnu.java.security.prng.LimitReachedException;
+import gnu.java.security.jce.prng.SecureRandomAdapter;
 import gnu.javax.crypto.prng.CSPRNG;
 
 import java.net.MalformedURLException;
@@ -53,6 +54,7 @@
     extends SecureRandomSpi
 {
   private final IRandom adaptee;
+  private boolean virgin = true;
 
   public CSPRNGSpi() throws ClassNotFoundException, MalformedURLException,
       NumberFormatException
@@ -62,21 +64,19 @@
     adaptee = CSPRNG.getSystemInstance();
   }
 
-  protected byte[] engineGenerateSeed(final int count)
+  protected byte[] engineGenerateSeed(final int numBytes)
   {
-    if (count < 0)
-      throw new IllegalArgumentException("count must be nonnegative");
-    byte[] buf = new byte[count];
-    if (count == 0)
-      return buf;
-    engineNextBytes(buf);
-    return buf;
+    return SecureRandomAdapter.getSeed(numBytes);
   }
 
   protected void engineNextBytes(final byte[] buffer)
   {
     if (buffer == null)
       throw new NullPointerException();
+    if (virgin)
+      {
+        engineSetSeed(engineGenerateSeed(32));
+      }
     try
       {
         adaptee.nextBytes(buffer, 0, buffer.length);
@@ -92,5 +92,6 @@
     if (seed == null)
       throw new NullPointerException();
     adaptee.addRandomBytes(seed, 0, seed.length);
+    virgin = false;
   }
 }
Index: gnu/javax/crypto/jce/prng/FortunaImpl.java
===================================================================
RCS file: 
/sources/classpath/classpath/gnu/javax/crypto/jce/prng/FortunaImpl.java,v
retrieving revision 1.2
diff -u -u -r1.2 FortunaImpl.java
--- gnu/javax/crypto/jce/prng/FortunaImpl.java  26 Jun 2006 13:30:14 -0000      
1.2
+++ gnu/javax/crypto/jce/prng/FortunaImpl.java  3 Feb 2009 20:45:12 -0000
@@ -39,6 +39,9 @@
 package gnu.javax.crypto.jce.prng;
 
 import gnu.java.security.prng.LimitReachedException;
+
+import gnu.java.security.jce.prng.SecureRandomAdapter;
+
 import gnu.javax.crypto.prng.Fortuna;
 
 import java.security.SecureRandomSpi;
@@ -47,19 +50,27 @@
 public final class FortunaImpl
     extends SecureRandomSpi
 {
+  private boolean virgin = true;
   private final Fortuna adaptee;
 
   public FortunaImpl()
   {
     adaptee = new Fortuna();
-    adaptee.init(Collections.singletonMap(Fortuna.SEED, new byte[0]));
   }
 
   protected void engineSetSeed(byte[] seed)
   {
     synchronized (adaptee)
       {
-        adaptee.addRandomBytes(seed);
+       if (virgin)
+         {
+            adaptee.init (Collections.singletonMap (Fortuna.SEED, seed));
+            virgin = false;
+          }
+        else
+          {
+            adaptee.addRandomBytes (seed);
+          }
       }
   }
 
@@ -67,6 +78,10 @@
   {
     synchronized (adaptee)
       {
+        if (virgin)
+          {
+            this.engineSetSeed(engineGenerateSeed(32));
+          }
         try
           {
             adaptee.nextBytes(buffer);
@@ -80,8 +95,6 @@
 
   protected byte[] engineGenerateSeed(int numbytes)
   {
-    byte[] seed = new byte[numbytes];
-    engineNextBytes(seed);
-    return seed;
+    return SecureRandomAdapter.getSeed(numBytes);
   }
 }
Index: gnu/javax/crypto/jce/prng/ICMRandomSpi.java
===================================================================
RCS file: 
/sources/classpath/classpath/gnu/javax/crypto/jce/prng/ICMRandomSpi.java,v
retrieving revision 1.5
diff -u -u -r1.5 ICMRandomSpi.java
--- gnu/javax/crypto/jce/prng/ICMRandomSpi.java 26 Jun 2006 13:30:14 -0000      
1.5
+++ gnu/javax/crypto/jce/prng/ICMRandomSpi.java 3 Feb 2009 20:45:12 -0000
@@ -40,6 +40,7 @@
 
 import gnu.java.security.Configuration;
 import gnu.java.security.Registry;
+import gnu.java.security.jce.prng.SecureRandomAdapter;
 import gnu.java.security.prng.LimitReachedException;
 import gnu.javax.crypto.cipher.IBlockCipher;
 import gnu.javax.crypto.prng.ICMGenerator;
@@ -107,19 +108,7 @@
 
   public byte[] engineGenerateSeed(int numBytes)
   {
-    if (Configuration.DEBUG)
-      log.entering(this.getClass().getName(), "engineGenerateSeed");
-    if (numBytes < 1)
-      {
-        if (Configuration.DEBUG)
-          log.exiting(this.getClass().getName(), "engineGenerateSeed");
-        return new byte[0];
-      }
-    byte[] result = new byte[numBytes];
-    this.engineNextBytes(result);
-    if (Configuration.DEBUG)
-      log.exiting(this.getClass().getName(), "engineGenerateSeed");
-    return result;
+    return SecureRandomAdapter.getSeed(numBytes);
   }
 
   public void engineNextBytes(byte[] bytes)
@@ -127,7 +116,7 @@
     if (Configuration.DEBUG)
       log.entering(this.getClass().getName(), "engineNextBytes");
     if (! adaptee.isInitialised())
-      this.engineSetSeed(new byte[0]);
+      this.engineSetSeed(engineGenerateSeed(32));
     while (true)
       {
         try
@@ -207,8 +196,8 @@
     System.arraycopy(material, 16, offset, 0, 16);
     attributes.put(ICMGenerator.OFFSET, offset);
     // specify the index
-    byte[] index = new byte[8];
-    System.arraycopy(material, 32, index, 0, 8);
+    byte[] index = new byte[4];
+    System.arraycopy(material, 32, index, 0, 4);
     attributes.put(ICMGenerator.SEGMENT_INDEX, new BigInteger(1, index));
     adaptee.init(attributes);
     if (Configuration.DEBUG)
Index: gnu/javax/crypto/jce/prng/UMacRandomSpi.java
===================================================================
RCS file: 
/sources/classpath/classpath/gnu/javax/crypto/jce/prng/UMacRandomSpi.java,v
retrieving revision 1.5
diff -u -u -r1.5 UMacRandomSpi.java
--- gnu/javax/crypto/jce/prng/UMacRandomSpi.java        26 Jun 2006 13:30:14 
-0000      1.5
+++ gnu/javax/crypto/jce/prng/UMacRandomSpi.java        3 Feb 2009 20:45:12 
-0000
@@ -41,6 +41,7 @@
 import gnu.java.security.Configuration;
 import gnu.java.security.Registry;
 import gnu.java.security.prng.LimitReachedException;
+import gnu.java.security.jce.prng.SecureRandomAdapter;
 import gnu.javax.crypto.cipher.IBlockCipher;
 import gnu.javax.crypto.prng.UMacGenerator;
 
@@ -57,6 +58,7 @@
     extends SecureRandomSpi
 {
   private static final Logger log = 
Logger.getLogger(UMacRandomSpi.class.getName());
+
   /** Class-wide prng to generate random material for the underlying prng. */
   private static final UMacGenerator prng; // blank final
   static
@@ -88,17 +90,13 @@
 
   public byte[] engineGenerateSeed(int numBytes)
   {
-    if (numBytes < 1)
-      return new byte[0];
-    byte[] result = new byte[numBytes];
-    this.engineNextBytes(result);
-    return result;
+    return SecureRandomAdapter.getSeed(numBytes);
   }
 
   public void engineNextBytes(byte[] bytes)
   {
     if (! adaptee.isInitialised())
-      this.engineSetSeed(new byte[0]);
+      engineSetSeed(engineGenerateSeed(32));
     while (true)
       {
         try
Index: gnu/javax/crypto/prng/ICMGenerator.java
===================================================================
RCS file: /sources/classpath/classpath/gnu/javax/crypto/prng/ICMGenerator.java,v
retrieving revision 1.4
diff -u -u -r1.4 ICMGenerator.java
--- gnu/javax/crypto/prng/ICMGenerator.java     2 Jul 2006 03:01:19 -0000       
1.4
+++ gnu/javax/crypto/prng/ICMGenerator.java     3 Feb 2009 20:45:13 -0000
@@ -263,6 +263,15 @@
     // C[0] = (s * (256^BLOCK_INDEX_LENGTH) + r) modulo (256^BLOCK_LENGTH)
     C0 = segmentNdx.multiply(TWO_FIFTY_SIX.pow(blockNdxLength))
                    .add(r).modPow(BigInteger.ONE, counterRange);
+    try
+      {
+        fillBlock();
+      }
+    catch (LimitReachedException impossible)
+      {
+       throw (InternalError)
+         new InternalError().initCause(impossible);
+      }
   }
 
   public void fillBlock() throws LimitReachedException

Reply via email to