1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 8141039 27 * @library /lib/testlibrary 28 * @summary SecureRandom supports multiple getInstance method including 29 * getInstanceStrong() method. This test verifies a set of possible 30 * cases for getInstance with different SecureRandom mechanism 31 * supported in Java. 32 * @run main GetInstanceTest 33 */ 34 import java.security.NoSuchAlgorithmException; 35 import java.security.NoSuchProviderException; 36 import java.security.SecureRandom; 37 import java.security.SecureRandomParameters; 38 import java.security.DrbgParameters; 39 import static java.security.DrbgParameters.Capability.*; 40 import java.security.Security; 41 import java.util.Arrays; 42 import jdk.testlibrary.Asserts; 43 44 public class GetInstanceTest { 45 46 private static final boolean PASS = true; 47 private static final String INVALID_ALGO = "INVALID"; 48 private static final String SUN_PROVIDER = "SUN"; 49 private static final String INVALID_PROVIDER = "INVALID"; 50 private static final String STRONG_ALG_SEC_PROP 51 = "securerandom.strongAlgorithms"; 52 private static final String DRBG_CONFIG = "securerandom.drbg.config"; 53 private static final String DRBG_CONFIG_VALUE 54 = Security.getProperty(DRBG_CONFIG); 55 main(String[] args)56 public static void main(String[] args) throws Exception { 57 58 boolean success = true; 59 // Only accepted failure is NoSuchAlgorithmException. 60 // For any other failure the test case will fail here. 61 SecureRandom sr = matchExc(() -> SecureRandom.getInstanceStrong(), 62 PASS, NoSuchAlgorithmException.class, 63 "PASS - Undefined security Property " 64 + "'securerandom.strongAlgorithms'"); 65 System.out.format("Current platform supports mechanism: '%s' through " 66 + "provider: '%s' for the method getInstanceStrong().", 67 sr.getAlgorithm(), sr.getProvider().getName()); 68 69 // DRBG name should appear with "securerandom.strongAlgorithms" 70 // security property. 71 String origDRBGConfig = Security.getProperty(STRONG_ALG_SEC_PROP); 72 if (!origDRBGConfig.contains("DRBG")) { 73 throw new RuntimeException("DRBG is not associated with default " 74 + "strong algorithm through security Property: " 75 + "'securerandom.strongAlgorithms'."); 76 } 77 try { 78 Security.setProperty(STRONG_ALG_SEC_PROP, "DRBG:SUN"); 79 sr = matchExc(() -> SecureRandom.getInstanceStrong(), 80 PASS, NoSuchAlgorithmException.class, 81 "PASS - Undefined security Property " 82 + "'securerandom.strongAlgorithms'"); 83 checkAttributes(sr, "DRBG"); 84 } finally { 85 Security.setProperty(STRONG_ALG_SEC_PROP, origDRBGConfig); 86 } 87 88 for (String mech : new String[]{ 89 "SHA1PRNG", "Hash_DRBG", "HMAC_DRBG", "CTR_DRBG", INVALID_ALGO,}) { 90 System.out.printf("%nTest SecureRandom mechanism: '%s'", mech); 91 try { 92 if (isDRBG(mech)) { 93 Security.setProperty(DRBG_CONFIG, mech); 94 } 95 verifyInstance(mech); 96 } catch (Exception e) { 97 e.printStackTrace(System.out); 98 success = false; 99 } finally { 100 Security.setProperty(DRBG_CONFIG, DRBG_CONFIG_VALUE); 101 } 102 } 103 if (!success) { 104 throw new RuntimeException("At least one test failed."); 105 } 106 } 107 verifyInstance(String mech)108 private static void verifyInstance(String mech) throws Exception { 109 110 String srAlgo = isDRBG(mech) ? "DRBG" : mech; 111 112 // Test for getInstance(algorithm) method. 113 // It should pass for all case other than invalid algorithm name. 114 // If it fails then the expected exception type should be 115 // NoSuchAlgorithmException. Any other Exception type occured will be 116 // treated as failure. 117 checkAttributes( 118 matchExc(() -> SecureRandom.getInstance(srAlgo), !(nsa(mech)), 119 NoSuchAlgorithmException.class, 120 String.format("PASS - It is expected to fail for" 121 + " getInstance(algorithm) when algorithm: '%s'" 122 + " is null or invalid.", mech)), mech); 123 // Test for getInstance(algorithm, provider) method. 124 checkAttributes( 125 matchExc(() -> SecureRandom.getInstance(srAlgo, 126 Security.getProvider(SUN_PROVIDER)), 127 !(nsa(mech)), 128 NoSuchAlgorithmException.class, 129 String.format("PASS - It is expected to fail for" 130 + " getInstance(algorithm, provider) when" 131 + " algorithm:'%s' is null or invalid.", mech)), 132 mech); 133 // Test for getInstance(algorithm, providerName) method. 134 checkAttributes( 135 matchExc(() -> SecureRandom.getInstance(srAlgo, SUN_PROVIDER), 136 !(nsa(mech)), NoSuchAlgorithmException.class, 137 String.format("PASS - It is expected to fail for " 138 + "getInstance(algorithm, providerName) when " 139 + "algorithm: '%s' is null or invalid.", mech)), 140 mech); 141 // Test for getInstance(algorithm, providerName) method. 142 checkAttributes( 143 matchExc(() -> SecureRandom.getInstance( 144 srAlgo, INVALID_PROVIDER), 145 !PASS, NoSuchProviderException.class, 146 String.format("PASS - It is expected to fail for " 147 + "getInstance(algorithm, providerName) when " 148 + "provider name: '%s' is invalid and " 149 + "algorithm: '%s'", INVALID_PROVIDER, mech)), 150 mech); 151 152 // Run the test for a set of SecureRandomParameters 153 for (SecureRandomParameters param : Arrays.asList(null, 154 DrbgParameters.instantiation(-1, NONE, null))) { 155 156 System.out.printf("%nRunning DRBG param getInstance() methods " 157 + "for algorithm: %s and DRBG param type: %s", mech, 158 (param != null) ? param.getClass().getName() : param); 159 160 // Following Test are applicable for new DRBG methods only. 161 // Test for getInstance(algorithm, params) method. 162 // Tests are expected to pass for DRBG type with valid parameter 163 // If it fails the expected exception type is derived from 164 // getExcType(mech, param) method. If exception type is not 165 // expected then the test will be considered as failure. 166 checkAttributes( 167 matchExc(() -> SecureRandom.getInstance(srAlgo, param), 168 (isDRBG(mech)) && (isValidDRBGParam(param)), 169 getExcType(mech, param), 170 String.format("PASS - It is expected to fail " 171 + "for getInstance(algorithm, params) " 172 + "for algorithm: %s and parameter: %s", 173 mech, param)), 174 mech); 175 // Test for getInstance(algorithm, params, provider) method. 176 checkAttributes( 177 matchExc(() -> SecureRandom.getInstance(srAlgo, param, 178 Security.getProvider(SUN_PROVIDER)), 179 (isDRBG(mech)) && (isValidDRBGParam(param)), 180 getExcType(mech, param), 181 String.format("PASS - It is expected to fail " 182 + "for getInstance(algorithm, params, " 183 + "provider) for algorithm: %s and " 184 + "parameter: %s", mech, param)), 185 mech); 186 // Test for getInstance(algorithm, params, providerName) method. 187 checkAttributes( 188 matchExc(() -> SecureRandom.getInstance(srAlgo, param, 189 SUN_PROVIDER), 190 (isDRBG(mech)) && (isValidDRBGParam(param)), 191 getExcType(mech, param), 192 String.format("PASS - It is expected to fail " 193 + "for getInstance(algorithm, params, " 194 + "providerName) for algorithm: %s and " 195 + "parameter: %s", mech, param)), mech); 196 // getInstance(algorithm, params, providerName) when 197 // providerName is invalid 198 checkAttributes( 199 matchExc(() -> SecureRandom.getInstance(srAlgo, param, 200 INVALID_PROVIDER), 201 !PASS, ((param == null) 202 ? IllegalArgumentException.class 203 : NoSuchProviderException.class), 204 String.format("PASS - It is expected to fail " 205 + "for getInstance(algorithm, params, " 206 + "providerName) when param is null or" 207 + " provider: %s is invalid for " 208 + "algorithm: '%s'", INVALID_PROVIDER, 209 mech)), mech); 210 // getInstance(algorithm, params, provider) when provider=null 211 checkAttributes( 212 matchExc(() -> SecureRandom.getInstance(srAlgo, param, 213 (String) null), 214 !PASS, IllegalArgumentException.class, 215 String.format("PASS - It is expected to fail " 216 + "for getInstance(algorithm, params, " 217 + "providerName) when provider name " 218 + "is null")), mech); 219 // getInstance(algorithm, params, providerName) when 220 // providerName is empty. 221 checkAttributes( 222 matchExc(() -> SecureRandom.getInstance( 223 srAlgo, param, ""), 224 !PASS, IllegalArgumentException.class, 225 String.format("PASS - It is expected to fail " 226 + "for getInstance(algorithm, params, " 227 + "providerName) when provider name " 228 + "is empty")), mech); 229 } 230 } 231 isValidDRBGParam(SecureRandomParameters param)232 private static boolean isValidDRBGParam(SecureRandomParameters param) { 233 return (param instanceof DrbgParameters.Instantiation); 234 } 235 236 /** 237 * If the mechanism should occur NoSuchAlgorithmException. 238 */ nsa(String mech)239 private static boolean nsa(String mech) { 240 return mech.equals(INVALID_ALGO); 241 } 242 243 /** 244 * Verify if the mechanism is DRBG type. 245 * @param mech Mechanism name 246 * @return True if the mechanism name is DRBG type else False. 247 */ isDRBG(String mech)248 private static boolean isDRBG(String mech) { 249 return mech.contains("_DRBG"); 250 } 251 252 /** 253 * Type of exception expected for a SecureRandom instance when exception 254 * occurred while calling getInstance method with a fixed set of parameter. 255 * @param mech Mechanism used to create a SecureRandom instance 256 * @param param Parameter to getInstance() method 257 * @return Exception type expected 258 */ getExcType(String mech, SecureRandomParameters param)259 private static Class getExcType(String mech, SecureRandomParameters param) { 260 return ((isDRBG(mech) && !isValidDRBGParam(param)) || param == null) 261 ? IllegalArgumentException.class 262 : NoSuchAlgorithmException.class; 263 } 264 265 private interface RunnableCode { 266 run()267 SecureRandom run() throws Exception; 268 } 269 270 /** 271 * Execute a given code block and verify, if the exception type is expected. 272 * @param r Code block to run 273 * @param ex Expected exception type 274 * @param shouldPass If the code execution expected to pass without failure 275 * @param msg Message to log in case of expected failure 276 */ matchExc(RunnableCode r, boolean shouldPass, Class ex, String msg)277 private static SecureRandom matchExc(RunnableCode r, boolean shouldPass, 278 Class ex, String msg) { 279 SecureRandom sr = null; 280 try { 281 sr = r.run(); 282 if (!shouldPass) { 283 throw new RuntimeException("Excecution should fail here."); 284 } 285 } catch (Exception e) { 286 System.out.printf("%nOccured exception: %s - Expected exception: %s" 287 + " : ", e.getClass(), ex.getCanonicalName()); 288 if (ex.isAssignableFrom(e.getClass())) { 289 System.out.printf("%n%s : Expected Exception: %s : ", 290 e.getClass(), msg); 291 } else if (shouldPass) { 292 throw new RuntimeException(e); 293 } else { 294 System.out.printf("%nIgnore the following exception: %s%n", 295 e.getMessage()); 296 } 297 } 298 return sr; 299 } 300 301 /** 302 * Check specific attributes of a SecureRandom instance. 303 */ checkAttributes(SecureRandom sr, String mech)304 private static void checkAttributes(SecureRandom sr, String mech) { 305 if (sr == null) { 306 return; 307 } 308 Asserts.assertEquals(sr.getAlgorithm(), (isDRBG(mech) ? "DRBG" : mech)); 309 Asserts.assertEquals(sr.getProvider().getName(), SUN_PROVIDER); 310 } 311 312 } 313