# HG changeset patch # User weijun # Date 1465265459 -28800 # Node ID 971a7101da5b51a1f7de122b5d10e17e537d9afa # Parent 21057752f32449605548a2c1c778e3eec2ee17ab 8157308: Make AbstractDrbg non-Serializable Reviewed-by: mullan diff -r 21057752f324 -r 971a7101da5b jdk/src/java.base/share/classes/sun/security/provider/AbstractDrbg.java --- a/jdk/src/java.base/share/classes/sun/security/provider/AbstractDrbg.java Mon Jun 06 16:46:54 2016 -0700 +++ b/jdk/src/java.base/share/classes/sun/security/provider/AbstractDrbg.java Tue Jun 07 10:10:59 2016 +0800 @@ -33,12 +33,13 @@ import static java.security.DrbgParameters.Capability.*; /** - * The abstract base class for all DRBGs. + * The abstract base class for all DRBGs. It is used as {@link DRBG#impl}. *

- * This class creates 5 new abstract methods. 3 are defined by the SP800-90A: + * This class has 5 abstract methods. 3 are defined by SP800-90A: *

    *
  1. {@link #generateAlgorithm(byte[], byte[])} - *
  2. {@link #reseedAlgorithm(byte[], byte[])} (might not be supported) + *
  3. {@link #reseedAlgorithm(byte[], byte[])} (In fact this is not an + * abstract method, but any DRBG supporting reseeding must override it.) *
  4. {@link #instantiateAlgorithm(byte[])} *
* and 2 for implementation purpose: @@ -46,18 +47,19 @@ *
  • {@link #initEngine()} *
  • {@link #chooseAlgorithmAndStrength} * - * All existing {@link SecureRandomSpi} methods are implemented based on the - * methods above as final. The initialization process is divided into 2 phases: - * configuration is eagerly called to set up parameters, and instantiation - * is lazily called only when nextBytes or reseed is called. + * Although this class is not a child class of {@link SecureRandomSpi}, it + * implements all abstract methods there as final. + *

    + * The initialization process of a DRBG is divided into 2 phases: + * {@link #configure configuration} is eagerly called to set up parameters, + * and {@link #instantiateIfNecessary instantiation} is lazily called only + * when nextBytes or reseed is called. *

    * SecureRandom methods like reseed and nextBytes are not thread-safe. * An implementation is required to protect shared access to instantiate states - * (instantiated, nonce) and DRBG states (v, c, key, reseedCounter). + * (instantiated, nonce) and DRBG states (v, c, key, reseedCounter, etc). */ -public abstract class AbstractDrbg extends SecureRandomSpi { - - private static final long serialVersionUID = 9L; +public abstract class AbstractDrbg { /** * This field is not null if {@code -Djava.security.debug=securerandom} is @@ -69,7 +71,7 @@ // Common working status - private transient boolean instantiated = false; + private boolean instantiated = false; /** * Reseed counter of a DRBG instance. A mechanism should increment it @@ -78,7 +80,7 @@ * * Volatile, will be used in a double checked locking. */ - protected transient volatile int reseedCounter = 0; + protected volatile int reseedCounter = 0; // Mech features. If not same as below, must be redefined in constructor. @@ -170,7 +172,7 @@ /** * Algorithm used by this instance (SHA-512 or AES-256). Must be assigned * in {@link #chooseAlgorithmAndStrength}. This field is used in - * {@link #toString()} and {@link DRBG#algorithmName}. + * {@link #toString()}. */ protected String algorithm; @@ -217,7 +219,7 @@ * After instantiation, this field is not null. Do not modify it * in a mechanism. */ - protected transient byte[] nonce; + protected byte[] nonce; /** * Requested nonce in {@link MoreDrbgParameters}. If set to null, @@ -237,7 +239,7 @@ * {@link #configure(SecureRandomParameters)}. This field * can be null. {@link #getEntropyInput} will take care of null check. */ - private transient EntropySource es; + private EntropySource es; // Five abstract methods for SP 800-90A DRBG @@ -286,10 +288,7 @@ /** * Initiates security engines ({@code MessageDigest}, {@code Mac}, - * or {@code Cipher}). Must be called in deserialization. Please note - * that before instantiation the algorithm might not be available yet. - * In this case, just return and this method will be called - * automatically at instantiation. + * or {@code Cipher}). This method is called during instantiation. */ protected abstract void initEngine(); @@ -331,13 +330,11 @@ // SecureRandomSpi methods taken care of here. All final. - @Override protected final void engineNextBytes(byte[] result) { engineNextBytes(result, DrbgParameters.nextBytes( -1, predictionResistanceFlag, null)); } - @Override protected final void engineNextBytes( byte[] result, SecureRandomParameters params) { @@ -402,7 +399,6 @@ } } - @Override public final void engineReseed(SecureRandomParameters params) { if (debug != null) { debug.println(this, "reseed with params"); @@ -454,7 +450,6 @@ * @param numBytes the number of seed bytes to generate. * @return the seed bytes. */ - @Override public final byte[] engineGenerateSeed(int numBytes) { byte[] b = new byte[numBytes]; SeedGenerator.generateSeed(b); @@ -469,7 +464,6 @@ * * @param input the seed */ - @Override public final synchronized void engineSetSeed(byte[] input) { if (debug != null) { debug.println(this, "setSeed"); @@ -598,7 +592,6 @@ * * @return the curent configuration */ - @Override protected SecureRandomParameters engineGetParameters() { // Or read from variable. return DrbgParameters.instantiation( @@ -631,7 +624,8 @@ this.es = m.es; this.requestedAlgorithm = m.algorithm; this.usedf = m.usedf; - params = m.config; + params = DrbgParameters.instantiation(m.strength, + m.capability, m.personalizationString); } if (params != null) { if (params instanceof DrbgParameters.Instantiation) { diff -r 21057752f324 -r 971a7101da5b jdk/src/java.base/share/classes/sun/security/provider/AbstractHashDrbg.java --- a/jdk/src/java.base/share/classes/sun/security/provider/AbstractHashDrbg.java Mon Jun 06 16:46:54 2016 -0700 +++ b/jdk/src/java.base/share/classes/sun/security/provider/AbstractHashDrbg.java Tue Jun 07 10:10:59 2016 +0800 @@ -32,8 +32,6 @@ public abstract class AbstractHashDrbg extends AbstractDrbg { - private static final long serialVersionUID = 9L; - protected int outLen; protected int seedLen; diff -r 21057752f324 -r 971a7101da5b jdk/src/java.base/share/classes/sun/security/provider/CtrDrbg.java --- a/jdk/src/java.base/share/classes/sun/security/provider/CtrDrbg.java Mon Jun 06 16:46:54 2016 -0700 +++ b/jdk/src/java.base/share/classes/sun/security/provider/CtrDrbg.java Tue Jun 07 10:10:59 2016 +0800 @@ -28,14 +28,12 @@ import javax.crypto.Cipher; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.SecretKeySpec; -import java.io.IOException; import java.security.*; import java.util.Arrays; import java.util.Locale; public class CtrDrbg extends AbstractDrbg { - private static final long serialVersionUID = 9L; private static final int AES_LIMIT; static { @@ -47,7 +45,7 @@ } } - private transient Cipher cipher; + private Cipher cipher; private String cipherAlg; private String keyAlg; @@ -57,8 +55,8 @@ private int keyLen; private int seedLen; - private transient byte[] v; - private transient byte[] k; + private byte[] v; + private byte[] k; public CtrDrbg(SecureRandomParameters params) { mechName = "CTR_DRBG"; @@ -165,7 +163,7 @@ protected void initEngine() { try { /* - * Use the local SUN implementation to avoid native + * Use the local SunJCE implementation to avoid native * performance overhead. */ cipher = Cipher.getInstance(cipherAlg, "SunJCE"); @@ -463,12 +461,6 @@ // Step 8. Return } - private void readObject(java.io.ObjectInputStream s) - throws IOException, ClassNotFoundException { - s.defaultReadObject (); - initEngine(); - } - @Override public String toString() { return super.toString() + "," diff -r 21057752f324 -r 971a7101da5b jdk/src/java.base/share/classes/sun/security/provider/DRBG.java --- a/jdk/src/java.base/share/classes/sun/security/provider/DRBG.java Mon Jun 06 16:46:54 2016 -0700 +++ b/jdk/src/java.base/share/classes/sun/security/provider/DRBG.java Tue Jun 07 10:10:59 2016 +0800 @@ -25,6 +25,7 @@ package sun.security.provider; +import java.io.IOException; import java.security.AccessController; import java.security.DrbgParameters; import java.security.PrivilegedAction; @@ -61,11 +62,12 @@ private static final long serialVersionUID = 9L; - private final AbstractDrbg impl; + private transient AbstractDrbg impl; - private final String mechName; - - private final String algorithmName; + /** + * @serial + */ + private final MoreDrbgParameters mdp; public DRBG(SecureRandomParameters params) { @@ -91,7 +93,7 @@ // Can be configured with a security property String config = AccessController.doPrivileged((PrivilegedAction) - () -> Security.getProperty(PROP_NAME)); + () -> Security.getProperty(PROP_NAME)); if (config != null && !config.isEmpty()) { for (String part : config.split(",")) { @@ -151,8 +153,9 @@ if (params != null) { // MoreDrbgParameters is used for testing. if (params instanceof MoreDrbgParameters) { - MoreDrbgParameters m = (MoreDrbgParameters)params; - params = m.config; + MoreDrbgParameters m = (MoreDrbgParameters) params; + params = DrbgParameters.instantiation(m.strength, + m.capability, m.personalizationString); // No need to check null for es and nonce, they are still null es = m.es; @@ -197,26 +200,27 @@ usedf = true; } - MoreDrbgParameters m = new MoreDrbgParameters( + mdp = new MoreDrbgParameters( es, mech, algorithm, nonce, usedf, DrbgParameters.instantiation(strength, cap, ps)); - switch (mech.toLowerCase(Locale.ROOT)) { + createImpl(); + } + + private void createImpl() { + switch (mdp.mech.toLowerCase(Locale.ROOT)) { case "hash_drbg": - impl = new HashDrbg(m); + impl = new HashDrbg(mdp); break; case "hmac_drbg": - impl = new HmacDrbg(m); + impl = new HmacDrbg(mdp); break; case "ctr_drbg": - impl = new CtrDrbg(m); + impl = new CtrDrbg(mdp); break; default: - throw new IllegalArgumentException("Unsupported mech: " + mech); + throw new IllegalArgumentException("Unsupported mech: " + mdp.mech); } - - mechName = mech; - algorithmName = impl.algorithm; } @Override @@ -268,4 +272,13 @@ + " cannot be provided more than once in " + PROP_NAME); } } + + private void readObject(java.io.ObjectInputStream s) + throws IOException, ClassNotFoundException { + s.defaultReadObject(); + if (mdp.mech == null) { + throw new IllegalArgumentException("Input data is corrupted"); + } + createImpl(); + } } diff -r 21057752f324 -r 971a7101da5b jdk/src/java.base/share/classes/sun/security/provider/HashDrbg.java --- a/jdk/src/java.base/share/classes/sun/security/provider/HashDrbg.java Mon Jun 06 16:46:54 2016 -0700 +++ b/jdk/src/java.base/share/classes/sun/security/provider/HashDrbg.java Tue Jun 07 10:10:59 2016 +0800 @@ -25,7 +25,6 @@ package sun.security.provider; -import java.io.IOException; import java.math.BigInteger; import java.security.DigestException; import java.security.MessageDigest; @@ -36,15 +35,13 @@ public class HashDrbg extends AbstractHashDrbg { - private static final long serialVersionUID = 9L; - private static final byte[] ZERO = new byte[1]; private static final byte[] ONE = new byte[]{1}; - private transient MessageDigest digest; + private MessageDigest digest; - private transient byte[] v; - private transient byte[] c; + private byte[] v; + private byte[] c; public HashDrbg(SecureRandomParameters params) { mechName = "Hash_DRBG"; @@ -267,10 +264,4 @@ // Step 5: No need to truncate // Step 6: Return } - - private void readObject(java.io.ObjectInputStream s) - throws IOException, ClassNotFoundException { - s.defaultReadObject (); - initEngine(); - } } diff -r 21057752f324 -r 971a7101da5b jdk/src/java.base/share/classes/sun/security/provider/HmacDrbg.java --- a/jdk/src/java.base/share/classes/sun/security/provider/HmacDrbg.java Mon Jun 06 16:46:54 2016 -0700 +++ b/jdk/src/java.base/share/classes/sun/security/provider/HmacDrbg.java Tue Jun 07 10:10:59 2016 +0800 @@ -27,7 +27,6 @@ import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; -import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; @@ -36,14 +35,12 @@ public class HmacDrbg extends AbstractHashDrbg { - private static final long serialVersionUID = 9L; - - private transient Mac mac; + private Mac mac; private String macAlg; - private transient byte[] v; - private transient byte[] k; + private byte[] v; + private byte[] k; public HmacDrbg(SecureRandomParameters params) { mechName = "HMAC_DRBG"; @@ -101,6 +98,10 @@ protected void initEngine() { macAlg = "HmacSHA" + algorithm.substring(4); try { + /* + * Use the local SunJCE implementation to avoid native + * performance overhead. + */ mac = Mac.getInstance(macAlg, "SunJCE"); } catch (NoSuchProviderException | NoSuchAlgorithmException e) { // Fallback to any available. @@ -194,10 +195,4 @@ // Step 8. Return } - - private void readObject(java.io.ObjectInputStream s) - throws IOException, ClassNotFoundException { - s.defaultReadObject (); - initEngine(); - } } diff -r 21057752f324 -r 971a7101da5b jdk/src/java.base/share/classes/sun/security/provider/MoreDrbgParameters.java --- a/jdk/src/java.base/share/classes/sun/security/provider/MoreDrbgParameters.java Mon Jun 06 16:46:54 2016 -0700 +++ b/jdk/src/java.base/share/classes/sun/security/provider/MoreDrbgParameters.java Tue Jun 07 10:10:59 2016 +0800 @@ -25,20 +25,30 @@ package sun.security.provider; +import java.io.IOException; +import java.io.Serializable; import java.security.DrbgParameters; import java.security.SecureRandomParameters; /** - * Extra non-standard parameters that can be used by DRBGs. + * Exported and non-exported parameters that can be used by DRBGs. */ -public class MoreDrbgParameters implements SecureRandomParameters { +public class MoreDrbgParameters implements SecureRandomParameters, Serializable { + + private static final long serialVersionUID = 9L; + + final transient EntropySource es; final String mech; final String algorithm; - final EntropySource es; - final byte[] nonce; final boolean usedf; - final DrbgParameters.Instantiation config; + final int strength; + final DrbgParameters.Capability capability; + + // The following 2 fields will be reassigned in readObject and + // thus cannot be final + byte[] nonce; + byte[] personalizationString; /** * Creates a new {@code MoreDrbgParameters} object. @@ -61,13 +71,31 @@ this.mech = mech; this.algorithm = algorithm; this.es = es; - this.nonce = nonce; + this.nonce = (nonce == null) ? null : nonce.clone(); this.usedf = usedf; - this.config = config; + + this.strength = config.getStrength(); + this.capability = config.getCapability(); + this.personalizationString = config.getPersonalizationString(); } @Override public String toString() { - return mech + "," + algorithm + "," + usedf + "," + config; + return mech + "," + algorithm + "," + usedf + "," + strength + + "," + capability + "," + personalizationString; + } + + private void readObject(java.io.ObjectInputStream s) + throws IOException, ClassNotFoundException { + s.defaultReadObject(); + if (nonce != null) { + nonce = nonce.clone(); + } + if (personalizationString != null) { + personalizationString = personalizationString.clone(); + } + if (capability == null) { + throw new IllegalArgumentException("Input data is corrupted"); + } } } diff -r 21057752f324 -r 971a7101da5b jdk/test/sun/security/provider/SecureRandom/AbstractDrbg/SpecTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/provider/SecureRandom/AbstractDrbg/SpecTest.java Tue Jun 07 10:10:59 2016 +0800 @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8051408 8157308 + * @modules java.base/sun.security.provider + * @build java.base/sun.security.provider.S + * @run main SpecTest + * @summary check the AbstractDrbg API etc + */ + +import java.security.*; +import sun.security.provider.S; +import static java.security.DrbgParameters.Capability.*; + +/** + * This test makes sure the AbstractDrbg API works as specified. It also + * checks the SecureRandom API. + * + * The implementations must be patched into java.base/sun.security.provider + * because AbstractDrbg is not a public interface. + */ +public class SpecTest { + + public static void main(String args[]) throws Exception { + + // getInstance from a provider. + + Provider p = new All("A", 0, ""); + byte[] bytes = new byte[100]; + + // A non-DRBG + iae(() -> SecureRandom.getInstance("S1", null, p)); + nsae(() -> SecureRandom.getInstance("S1", + new SecureRandomParameters() {}, p)); + + SecureRandom s1 = SecureRandom.getInstance("S1", p); + if (s1.getParameters() != null) { + throw new Exception(); + } + + iae(() -> s1.nextBytes(bytes, null)); + uoe(() -> s1.nextBytes(bytes, new SecureRandomParameters() {})); + uoe(() -> s1.reseed()); + iae(() -> s1.reseed(null)); + uoe(() -> s1.reseed(new SecureRandomParameters() {})); + + // A weak DRBG + iae(() -> SecureRandom.getInstance("S2", null, p)); + nsae(() -> SecureRandom.getInstance("S2", + new SecureRandomParameters() {}, p)); + nsae(() -> SecureRandom.getInstance("S2", + DrbgParameters.instantiation(256, NONE, null), p)); + nsae(() -> SecureRandom.getInstance("S2", + DrbgParameters.instantiation(-1, PR_AND_RESEED, null), p)); + nsae(() -> SecureRandom.getInstance("S2", + DrbgParameters.instantiation(-1, RESEED_ONLY, null), p)); + + SecureRandom s2 = SecureRandom.getInstance("S2", + DrbgParameters.instantiation(-1, NONE, null), p); + equals(s2, "S2,SQUEEZE,128,none"); + equals(s2.getParameters(), "128,none,null"); + + npe(() -> s2.nextBytes(null)); + iae(() -> s2.nextBytes(bytes, null)); + iae(() -> s2.nextBytes(bytes, new SecureRandomParameters() {})); + uoe(() -> s2.reseed()); + iae(() -> s2.reseed(null)); + + iae(() -> s2.nextBytes(bytes, + DrbgParameters.nextBytes(-1, false, new byte[101]))); + s2.nextBytes(new byte[101], + DrbgParameters.nextBytes(-1, false, new byte[100])); + s2.nextBytes(bytes, + DrbgParameters.nextBytes(-1, false, new byte[100])); + + // A strong DRBG + iae(() -> SecureRandom.getInstance("S3", null, p)); + nsae(() -> SecureRandom.getInstance("S3", + new SecureRandomParameters() {}, p)); + SecureRandom.getInstance("S3", + DrbgParameters.instantiation(192, PR_AND_RESEED, null), p); + + SecureRandom s3 = SecureRandom.getInstance("S3", p); + equals(s3, "S3,SQUEEZE,128,reseed_only"); + equals(s3.getParameters(), "128,reseed_only,null"); + + iae(() -> s3.nextBytes(bytes, + DrbgParameters.nextBytes(192, false, null))); + iae(() -> s3.nextBytes(bytes, + DrbgParameters.nextBytes(112, true, null))); + iae(() -> s3.reseed(new SecureRandomParameters() {})); + + SecureRandom s32 = SecureRandom.getInstance( + "S3", DrbgParameters.instantiation(192, PR_AND_RESEED, null), p); + equals(s32, "S3,SQUEEZE,192,pr_and_reseed"); + equals(s32.getParameters(), "192,pr_and_reseed,null"); + + s32.nextBytes(bytes, DrbgParameters.nextBytes(192, false, null)); + s32.nextBytes(bytes, DrbgParameters.nextBytes(112, true, null)); + s32.reseed(); + s32.reseed(DrbgParameters.reseed(true, new byte[100])); + + // getInstance from competitive providers. + + Provider l = new Legacy("L", 0, ""); + Provider w = new Weak("W", 0, ""); + Provider s = new Strong("S", 0, ""); + + Security.addProvider(l); + Security.addProvider(w); + Security.addProvider(s); + + SecureRandom s4; + + try { + s4 = SecureRandom.getInstance("S"); + if (s4.getProvider() != l) { + throw new Exception(); + } + + nsae(() -> SecureRandom.getInstance( + "S", DrbgParameters.instantiation(256, NONE, null))); + + s4 = SecureRandom.getInstance( + "S", DrbgParameters.instantiation(192, NONE, null)); + if (s4.getProvider() != s) { + throw new Exception(); + } + + s4 = SecureRandom.getInstance( + "S", DrbgParameters.instantiation(128, PR_AND_RESEED, null)); + if (s4.getProvider() != s) { + throw new Exception(); + } + + s4 = SecureRandom.getInstance( + "S", DrbgParameters.instantiation(128, RESEED_ONLY, null)); + if (s4.getProvider() != s) { + throw new Exception(); + } + + s4 = SecureRandom.getInstance( + "S", DrbgParameters.instantiation(128, NONE, null)); + if (s4.getProvider() != w) { + throw new Exception(); + } + } finally { + Security.removeProvider("L"); + Security.removeProvider("W"); + Security.removeProvider("S"); + } + } + + public static class All extends Provider { + protected All(String name, double version, String info) { + super(name, version, info); + put("SecureRandom.S1", S.S1.class.getName()); + put("SecureRandom.S2", S.S2.class.getName()); + put("SecureRandom.S3", S.S3.class.getName()); + } + } + + // Providing S with no params support + public static class Legacy extends Provider { + protected Legacy(String name, double version, String info) { + super(name, version, info); + put("SecureRandom.S", S.S1.class.getName()); + } + } + + public static class Weak extends Provider { + protected Weak(String name, double version, String info) { + super(name, version, info); + put("SecureRandom.S", S.S2.class.getName()); + } + } + + public static class Strong extends Provider { + protected Strong(String name, double version, String info) { + super(name, version, info); + put("SecureRandom.S", S.S3.class.getName()); + } + } + + static void nsae(RunnableWithException r) throws Exception { + checkException(r, NoSuchAlgorithmException.class); + } + + static void iae(RunnableWithException r) throws Exception { + checkException(r, IllegalArgumentException.class); + } + + static void uoe(RunnableWithException r) throws Exception { + checkException(r, UnsupportedOperationException.class); + } + + static void npe(RunnableWithException r) throws Exception { + checkException(r, NullPointerException.class); + } + + interface RunnableWithException { + void run() throws Exception; + } + + static void checkException(RunnableWithException r, Class ex) + throws Exception { + try { + r.run(); + } catch (Exception e) { + if (ex.isAssignableFrom(e.getClass())) { + return; + } + throw e; + } + throw new Exception("No exception thrown"); + } + + static void equals(Object o, String s) throws Exception { + if (!o.toString().equals(s)) { + throw new Exception(o.toString() + " is not " + s); + } + } +} diff -r 21057752f324 -r 971a7101da5b jdk/test/sun/security/provider/SecureRandom/AbstractDrbg/java.base/sun/security/provider/S.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/provider/SecureRandom/AbstractDrbg/java.base/sun/security/provider/S.java Tue Jun 07 10:10:59 2016 +0800 @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.provider; + +import java.security.SecureRandomParameters; +import java.security.SecureRandomSpi; + +/** + * Read ../../../../SpecTest.java for details. + */ +public class S extends SecureRandomSpi { + + protected AbstractDrbg impl; + + // This is not a DRBG. + public static class S1 extends SecureRandomSpi { + @Override + protected void engineSetSeed(byte[] seed) { + } + + @Override + protected void engineNextBytes(byte[] bytes) { + } + + @Override + protected byte[] engineGenerateSeed(int numBytes) { + return new byte[numBytes]; + } + } + + // This is a weak DRBG. maximum strength is 128 and does + // not support prediction resistance or reseed. + public static class S2 extends S { + public S2(SecureRandomParameters params) { + impl = new Impl2(params); + } + } + + // This is a strong DRBG. + public static class S3 extends S { + public S3(SecureRandomParameters params) { + impl = new Impl3(params); + } + } + + // AbstractDrbg Implementations + + static class Impl3 extends AbstractDrbg { + + public Impl3(SecureRandomParameters params) { + supportPredictionResistance = true; + supportReseeding = true; + highestSupportedSecurityStrength = 192; + mechName = "S3"; + algorithm = "SQUEEZE"; + configure(params); + } + + protected void chooseAlgorithmAndStrength() { + if (requestedInstantiationSecurityStrength < 0) { + securityStrength = DEFAULT_STRENGTH; + } else { + securityStrength = requestedInstantiationSecurityStrength; + } + minLength = securityStrength / 8; + maxAdditionalInputLength = maxPersonalizationStringLength = 100; + } + + @Override + protected void initEngine() { + } + + @Override + protected void instantiateAlgorithm(byte[] ei) { + } + + @Override + protected void generateAlgorithm(byte[] result, byte[] additionalInput) { + } + + @Override + protected void reseedAlgorithm(byte[] ei, byte[] additionalInput) { + } + } + + static class Impl2 extends Impl3 { + public Impl2(SecureRandomParameters params) { + super(null); + mechName = "S2"; + highestSupportedSecurityStrength = 128; + supportPredictionResistance = false; + supportReseeding = false; + configure(params); + } + } + + // Overridden SecureRandomSpi methods + + @Override + protected void engineSetSeed(byte[] seed) { + impl.engineSetSeed(seed); + } + + @Override + protected void engineNextBytes(byte[] bytes) { + impl.engineNextBytes(bytes); + } + + @Override + protected byte[] engineGenerateSeed(int numBytes) { + return impl.engineGenerateSeed(numBytes); + } + + @Override + protected void engineNextBytes( + byte[] bytes, SecureRandomParameters params) { + impl.engineNextBytes(bytes, params); + } + + @Override + protected void engineReseed(SecureRandomParameters params) { + impl.engineReseed(params); + } + + @Override + protected SecureRandomParameters engineGetParameters() { + return impl.engineGetParameters(); + } + + @Override + public String toString() { + return impl.toString(); + } +} diff -r 21057752f324 -r 971a7101da5b jdk/test/sun/security/provider/SecureRandom/AbstractDrbgSpec.java --- a/jdk/test/sun/security/provider/SecureRandom/AbstractDrbgSpec.java Mon Jun 06 16:46:54 2016 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,310 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* @test - * @bug 8051408 - * @modules java.base/sun.security.provider - * @summary check the AbstractDrbg API etc - */ - -import java.security.*; -import sun.security.provider.AbstractDrbg; -import static java.security.DrbgParameters.Capability.*; - -/** - * This test makes sure the AbstractDrbg API works as specified. It also - * checks the SecureRandom API. - */ -public class AbstractDrbgSpec { - - public static void main(String args[]) throws Exception { - - // getInstance from a provider. - - Provider p = new All("A", 0, ""); - byte[] bytes = new byte[100]; - - // A non-DRBG - iae(() -> SecureRandom.getInstance("S1", null, p)); - nsae(() -> SecureRandom.getInstance("S1", - new SecureRandomParameters() {}, p)); - - SecureRandom s1 = SecureRandom.getInstance("S1", p); - if (s1.getParameters() != null) { - throw new Exception(); - } - - iae(() -> s1.nextBytes(bytes, null)); - uoe(() -> s1.nextBytes(bytes, new SecureRandomParameters() {})); - uoe(() -> s1.reseed()); - iae(() -> s1.reseed(null)); - uoe(() -> s1.reseed(new SecureRandomParameters() {})); - - // A weak DRBG - iae(() -> SecureRandom.getInstance("S2", null, p)); - nsae(() -> SecureRandom.getInstance("S2", - new SecureRandomParameters() {}, p)); - nsae(() -> SecureRandom.getInstance("S2", - DrbgParameters.instantiation(256, NONE, null), p)); - nsae(() -> SecureRandom.getInstance("S2", - DrbgParameters.instantiation(-1, PR_AND_RESEED, null), p)); - nsae(() -> SecureRandom.getInstance("S2", - DrbgParameters.instantiation(-1, RESEED_ONLY, null), p)); - - SecureRandom s2 = SecureRandom.getInstance("S2", - DrbgParameters.instantiation(-1, NONE, null), p); - equals(s2, "S2,SQUEEZE,128,none"); - equals(s2.getParameters(), "128,none,null"); - - npe(() -> s2.nextBytes(null)); - iae(() -> s2.nextBytes(bytes, null)); - iae(() -> s2.nextBytes(bytes, new SecureRandomParameters() {})); - uoe(() -> s2.reseed()); - iae(() -> s2.reseed(null)); - - iae(() -> s2.nextBytes(bytes, - DrbgParameters.nextBytes(-1, false, new byte[101]))); - s2.nextBytes(new byte[101], - DrbgParameters.nextBytes(-1, false, new byte[100])); - s2.nextBytes(bytes, - DrbgParameters.nextBytes(-1, false, new byte[100])); - - // A strong DRBG - iae(() -> SecureRandom.getInstance("S3", null, p)); - nsae(() -> SecureRandom.getInstance("S3", - new SecureRandomParameters() {}, p)); - SecureRandom.getInstance("S3", - DrbgParameters.instantiation(192, PR_AND_RESEED, null), p); - - SecureRandom s3 = SecureRandom.getInstance("S3", p); - equals(s3, "S3,SQUEEZE,128,reseed_only"); - equals(s3.getParameters(), "128,reseed_only,null"); - - iae(() -> s3.nextBytes(bytes, - DrbgParameters.nextBytes(192, false, null))); - iae(() -> s3.nextBytes(bytes, - DrbgParameters.nextBytes(112, true, null))); - iae(() -> s3.reseed(new SecureRandomParameters() {})); - - SecureRandom s32 = SecureRandom.getInstance( - "S3", DrbgParameters.instantiation(192, PR_AND_RESEED, null), p); - equals(s32, "S3,SQUEEZE,192,pr_and_reseed"); - equals(s32.getParameters(), "192,pr_and_reseed,null"); - - s32.nextBytes(bytes, DrbgParameters.nextBytes(192, false, null)); - s32.nextBytes(bytes, DrbgParameters.nextBytes(112, true, null)); - s32.reseed(); - s32.reseed(DrbgParameters.reseed(true, new byte[100])); - - // getInstance from competitive providers. - - Provider l = new Legacy("L", 0, ""); - Provider w = new Weak("W", 0, ""); - Provider s = new Strong("S", 0, ""); - - Security.addProvider(l); - Security.addProvider(w); - Security.addProvider(s); - - SecureRandom s4; - - try { - s4 = SecureRandom.getInstance("S"); - if (s4.getProvider() != l) { - throw new Exception(); - } - - nsae(() -> SecureRandom.getInstance( - "S", DrbgParameters.instantiation(256, NONE, null))); - - s4 = SecureRandom.getInstance( - "S", DrbgParameters.instantiation(192, NONE, null)); - if (s4.getProvider() != s) { - throw new Exception(); - } - - s4 = SecureRandom.getInstance( - "S", DrbgParameters.instantiation(128, PR_AND_RESEED, null)); - if (s4.getProvider() != s) { - throw new Exception(); - } - - s4 = SecureRandom.getInstance( - "S", DrbgParameters.instantiation(128, RESEED_ONLY, null)); - if (s4.getProvider() != s) { - throw new Exception(); - } - - s4 = SecureRandom.getInstance( - "S", DrbgParameters.instantiation(128, NONE, null)); - if (s4.getProvider() != w) { - throw new Exception(); - } - } finally { - Security.removeProvider("L"); - Security.removeProvider("W"); - Security.removeProvider("S"); - } - } - - public static class All extends Provider { - protected All(String name, double version, String info) { - super(name, version, info); - put("SecureRandom.S1", S1.class.getName()); - put("SecureRandom.S2", S2.class.getName()); - put("SecureRandom.S3", S3.class.getName()); - } - } - - // Providing S with no params support - public static class Legacy extends Provider { - protected Legacy(String name, double version, String info) { - super(name, version, info); - put("SecureRandom.S", S1.class.getName()); - } - } - - public static class Weak extends Provider { - protected Weak(String name, double version, String info) { - super(name, version, info); - put("SecureRandom.S", S2.class.getName()); - } - } - - public static class Strong extends Provider { - protected Strong(String name, double version, String info) { - super(name, version, info); - put("SecureRandom.S", S3.class.getName()); - } - } - - // This is not a DRBG. - public static class S1 extends SecureRandomSpi { - @Override - protected void engineSetSeed(byte[] seed) { - } - - @Override - protected void engineNextBytes(byte[] bytes) { - } - - @Override - protected byte[] engineGenerateSeed(int numBytes) { - return new byte[numBytes]; - } - } - - // This is a strong DRBG. - public static class S3 extends AbstractDrbg { - - public S3(SecureRandomParameters params) { - supportPredictionResistance = true; - supportReseeding = true; - highestSupportedSecurityStrength = 192; - mechName = "S3"; - algorithm = "SQUEEZE"; - configure(params); - } - protected void chooseAlgorithmAndStrength() { - if (requestedInstantiationSecurityStrength < 0) { - securityStrength = DEFAULT_STRENGTH; - } else { - securityStrength = requestedInstantiationSecurityStrength; - } - minLength = securityStrength / 8; - maxAdditionalInputLength = maxPersonalizationStringLength = 100; - } - - @Override - protected void initEngine() { - - } - - @Override - protected void instantiateAlgorithm(byte[] ei) { - - } - - @Override - protected void generateAlgorithm(byte[] result, byte[] additionalInput) { - - } - - @Override - protected void reseedAlgorithm(byte[] ei, byte[] additionalInput) { - - } - } - - // This is a weak DRBG. maximum strength is 128 and does - // not support prediction resistance or reseed. - public static class S2 extends S3 { - public S2(SecureRandomParameters params) { - super(null); - mechName = "S2"; - highestSupportedSecurityStrength = 128; - supportPredictionResistance = false; - supportReseeding = false; - configure(params); - } - } - - static void nsae(RunnableWithException r) throws Exception { - checkException(r, NoSuchAlgorithmException.class); - } - - static void iae(RunnableWithException r) throws Exception { - checkException(r, IllegalArgumentException.class); - } - - static void uoe(RunnableWithException r) throws Exception { - checkException(r, UnsupportedOperationException.class); - } - - static void npe(RunnableWithException r) throws Exception { - checkException(r, NullPointerException.class); - } - - interface RunnableWithException { - void run() throws Exception; - } - - static void checkException(RunnableWithException r, Class ex) - throws Exception { - try { - r.run(); - } catch (Exception e) { - if (ex.isAssignableFrom(e.getClass())) { - return; - } - throw e; - } - throw new Exception("No exception thrown"); - } - - static void equals(Object o, String s) throws Exception { - if (!o.toString().equals(s)) { - throw new Exception(o.toString() + " is not " + s); - } - } -} diff -r 21057752f324 -r 971a7101da5b jdk/test/sun/security/provider/SecureRandom/DRBGS11n.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/provider/SecureRandom/DRBGS11n.java Tue Jun 07 10:10:59 2016 +0800 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import sun.security.provider.DRBG; +import sun.security.provider.MoreDrbgParameters; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Field; + +/** + * @test + * @bug 8157308 + * @modules java.base/sun.security.provider + * @summary Make AbstractDrbg non-Serializable + * @run main DRBGS11n mech + * @run main DRBGS11n capability + */ +public class DRBGS11n { + + public static void main(String[] args) throws Exception { + + DRBG d = new DRBG(null); + Field f = DRBG.class.getDeclaredField("mdp"); + f.setAccessible(true); + MoreDrbgParameters mdp = (MoreDrbgParameters)f.get(d); + + // Corrupt the mech or capability fields inside DRBG#mdp. + f = MoreDrbgParameters.class.getDeclaredField(args[0]); + f.setAccessible(true); + f.set(mdp, null); + + try { + revive(d); + } catch (IllegalArgumentException iae) { + // Expected + return; + } + + throw new Exception("revive should fail"); + } + + static T revive(T in) throws Exception { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + new ObjectOutputStream(bout).writeObject(in); + return (T) new ObjectInputStream( + new ByteArrayInputStream(bout.toByteArray())).readObject(); + } +}