1 /* 2 * Copyright (c) 2018, 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 8200219 27 * @summary Negative tests for Key related Test with DiffieHellman, ECDH, XDH. 28 * It Tests, 29 * Use modified encoding while generating Public/Private Keys 30 * Short, long, unsupported keysize 31 * Invalid Algo names including Null 32 * Invalid provider names including Null 33 * Invalid curve names 34 * Invalid spec usage 35 * Arguments order <KeyExchangeAlgorithm> <Provider> <KeyGenAlgorithm> 36 * <keySize> <Curve*> 37 * @run main NegativeTest DiffieHellman SunJCE DiffieHellman 1024 38 * @run main NegativeTest ECDH SunEC EC 256 39 * @run main NegativeTest XDH SunEC XDH 255 X25519 40 * @run main NegativeTest XDH SunEC XDH 448 X448 41 */ 42 import java.math.BigInteger; 43 import java.security.InvalidAlgorithmParameterException; 44 import java.security.InvalidParameterException; 45 import java.security.KeyFactory; 46 import java.security.KeyPair; 47 import java.security.KeyPairGenerator; 48 import java.security.NoSuchAlgorithmException; 49 import java.security.NoSuchProviderException; 50 import java.security.Security; 51 import java.security.spec.InvalidKeySpecException; 52 import java.security.spec.NamedParameterSpec; 53 import java.security.spec.KeySpec; 54 import java.security.spec.PKCS8EncodedKeySpec; 55 import java.security.spec.X509EncodedKeySpec; 56 import java.security.spec.XECPrivateKeySpec; 57 import java.security.spec.XECPublicKeySpec; 58 import java.util.Arrays; 59 import javax.crypto.KeyAgreement; 60 61 public class NegativeTest { 62 63 public static void main(String[] args) throws Exception { 64 65 String kaAlgo = args[0]; 66 String provider = args[1]; 67 String kpgAlgo = args[2]; 68 int keySize = Integer.parseInt(args[3]); 69 String kpgInit = (args.length > 4) ? args[4] : args[2]; 70 testModifiedKeyEncodingTest(provider, kpgAlgo, kpgInit); 71 testInvalidKeyLen(provider, kaAlgo, kpgAlgo, kpgInit); 72 testInvalidKpgAlgo(provider, kaAlgo, keySize); 73 testInvalidKaAlgo(provider, kpgAlgo, keySize); 74 testInvalidProvider(kaAlgo, kpgAlgo, keySize); 75 if (!kaAlgo.equals("DiffieHellman")) { 76 testNamedParameter(provider, kpgAlgo); 77 } 78 if (kaAlgo.equals("XDH")) { 79 testInvalidSpec(provider, kpgAlgo, kpgInit); 80 testInCompatibleSpec(provider, kpgAlgo, kpgInit); 81 } 82 } 83 84 /** 85 * Generate keyPair based on KeyPairGenerator algorithm. 86 */ 87 private static KeyPair genKeyPair(String provider, String kpgAlgo, 88 String kpgInit) throws Exception { 89 90 KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgAlgo, 91 Security.getProvider(provider)); 92 switch (kpgInit) { 93 case "DiffieHellman": 94 kpg.initialize(512); 95 break; 96 case "EC": 97 kpg.initialize(256); 98 break; 99 case "X25519": 100 kpg.initialize(255); 101 break; 102 case "X448": 103 kpg.initialize(448); 104 break; 105 default: 106 throw new RuntimeException("Invalid Algo name " + kpgInit); 107 } 108 return kpg.generateKeyPair(); 109 } 110 111 private static void testModifiedKeyEncodingTest(String provider, 112 String kpgAlgo, String kpgInit) throws Exception { 113 114 KeyFactory kf = KeyFactory.getInstance(kpgAlgo, provider); 115 KeyPair kp = genKeyPair(provider, kpgAlgo, kpgInit); 116 // Test modified PrivateKey encoding 117 byte[] encoded = kp.getPrivate().getEncoded(); 118 byte[] modified = modifyEncoded(encoded); 119 PKCS8EncodedKeySpec priSpec = new PKCS8EncodedKeySpec(modified); 120 try { 121 // Generate PrivateKey with modified encoding 122 kf.generatePrivate(priSpec); 123 throw new RuntimeException( 124 "testModifiedKeyTest should fail but passed."); 125 } catch (InvalidKeySpecException e) { 126 System.out.printf("Expected InvalidKeySpecException for invalid " 127 + "PrivateKey %s%n and modified encoding: %s, %s%n", 128 byteArrayToHexString(encoded), 129 byteArrayToHexString(modified), e.getMessage()); 130 } 131 // Test modified PublicKey encoding 132 encoded = kp.getPublic().getEncoded(); 133 modified = modifyEncoded(encoded); 134 X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(modified); 135 try { 136 // Generate PublicKey with modified encoding 137 kf.generatePublic(pubSpec); 138 throw new RuntimeException( 139 "testModifiedKeyTest should fail but passed."); 140 } catch (InvalidKeySpecException e) { 141 System.out.printf("Expected InvalidKeySpecException for invalid " 142 + "PublicKey %s%n and modified encoding: %s, %s%n", 143 byteArrayToHexString(encoded), 144 byteArrayToHexString(modified), e.getMessage()); 145 } 146 } 147 148 /** 149 * Test with all Invalid key length. 150 */ 151 private static void testInvalidKeyLen(String provider, String kaAlgo, 152 String kpgAlgo, String kpgInit) throws Exception { 153 154 for (int keySize : selectInvalidKeylength(kpgInit)) { 155 try { 156 startKeyAgreement(provider, kaAlgo, kpgAlgo, keySize); 157 throw new RuntimeException( 158 "testInvalidKeyLen should fail but passed."); 159 } catch (InvalidParameterException e) { 160 System.out.printf("Expected InvalidParameterException for " 161 + "keyLength: %s, %s%n", keySize, e.getMessage()); 162 } 163 } 164 } 165 166 /** 167 * Test with all Invalid KeyPairGenerator algorithms. 168 */ 169 private static void testInvalidKpgAlgo(String provider, String algo, 170 int keySize) throws Exception { 171 172 for (String kpgAlgo : new String[]{null, " ", "", "NoSuchAlgorithm"}) { 173 try { 174 startKeyAgreement(provider, algo, kpgAlgo, keySize); 175 throw new RuntimeException( 176 "testInvalidKpgAlgo should fail but passed."); 177 } catch (NoSuchAlgorithmException e) { 178 System.out.printf("Expected NoSuchAlgorithmException for " 179 + "KeyAgreement algo: %s, %s%n", 180 kpgAlgo, e.getMessage()); 181 } catch (NullPointerException e) { 182 if (kpgAlgo == null) { 183 System.out.printf("Expected NullPointerException for " 184 + "KeyPairGenerator algo: %s, %s%n", 185 kpgAlgo, e.getMessage()); 186 continue; 187 } 188 throw new RuntimeException( 189 "Unknown failure in testInvalidKpgAlgo."); 190 } 191 } 192 } 193 194 /** 195 * Test with all Invalid KeyAgreement algorithms. 196 */ 197 private static void testInvalidKaAlgo(String provider, String kpgAlgo, 198 int keySize) throws Exception { 199 200 for (String algo : new String[]{null, " ", "", "NoSuchAlgorithm"}) { 201 try { 202 startKeyAgreement(provider, algo, kpgAlgo, keySize); 203 throw new RuntimeException( 204 "testInvalidKaAlgo should fail but passed."); 205 } catch (NoSuchAlgorithmException e) { 206 System.out.printf("Expected NoSuchAlgorithmException for " 207 + "KeyAgreement algo: %s, %s%n", algo, e.getMessage()); 208 } catch (NullPointerException e) { 209 if (algo == null) { 210 System.out.printf("Expected NullPointerException for " 211 + "KeyAgreement algo: %s, %s%n", 212 algo, e.getMessage()); 213 continue; 214 } 215 throw new RuntimeException( 216 "Unknown failure in testInvalidKaAlgo."); 217 } 218 } 219 } 220 221 /** 222 * Test with all Invalid Provider names. 223 */ 224 private static void testInvalidProvider(String kaAlgo, String kpgAlgo, 225 int keySize) throws Exception { 226 227 for (String provider : new String[]{null, " ", "", "NoSuchProvider"}) { 228 try { 229 startKeyAgreement(provider, kaAlgo, kpgAlgo, keySize); 230 throw new RuntimeException( 231 "testInvalidProvider should fail but passed."); 232 } catch (NoSuchProviderException e) { 233 System.out.printf("Expected NoSuchProviderException for " 234 + "Provider: %s, %s%n", provider, e.getMessage()); 235 } catch (IllegalArgumentException e) { 236 System.out.printf("Expected IllegalArgumentException for " 237 + "Provider: %s, %s%n", provider, e.getMessage()); 238 } 239 } 240 } 241 242 /** 243 * Test for (in)valid curve names as argument to NamedParameterSpec 244 */ 245 private static void testNamedParameter(String provider, String kpgAlgo) 246 throws Exception { 247 248 for (String name : new String[]{null, " ", "", "NoSuchCurve"}) { 249 try { 250 NamedParameterSpec spec = new NamedParameterSpec(name); 251 KeyPairGenerator kpg 252 = KeyPairGenerator.getInstance(kpgAlgo, provider); 253 kpg.initialize(spec); 254 kpg.generateKeyPair(); 255 throw new RuntimeException( 256 "testNamedParameter should fail but passed."); 257 } catch (NullPointerException e) { 258 if (name == null) { 259 System.out.printf("Expected NullPointerException for " 260 + "NamedParameterSpec name: %s, %s%n", 261 name, e.getMessage()); 262 continue; 263 } 264 throw new RuntimeException( 265 "Unknown failure in testNamedParameter."); 266 } catch (InvalidAlgorithmParameterException e) { 267 System.out.printf("Expected InvalidAlgorithmParameterException" 268 + " for NamedParameterSpec name: %s, %s%n", 269 name, e.getMessage()); 270 } 271 } 272 } 273 274 /** 275 * Test to generate Public/Private keys using (in)valid coordinate/scalar. 276 */ 277 private static void testInvalidSpec(String provider, 278 String kpgAlgo, String curve) throws Exception { 279 280 NamedParameterSpec spec = new NamedParameterSpec(curve); 281 KeyFactory kf = KeyFactory.getInstance(kpgAlgo, provider); 282 int validLen = curve.equalsIgnoreCase("X448") ? 56 : 32; 283 for (byte[] scalarBytes : new byte[][]{null, new byte[]{}, 284 new byte[32], new byte[56], new byte[65535]}) { 285 try { 286 KeySpec privateSpec = new XECPrivateKeySpec(spec, scalarBytes); 287 kf.generatePrivate(privateSpec); 288 if (scalarBytes.length != validLen) { 289 throw new RuntimeException(String.format("testInvalidSpec " 290 + "should fail but passed when Scalar bytes length " 291 + "!= %s for curve %s", validLen, curve)); 292 } 293 } catch (NullPointerException e) { 294 if (scalarBytes == null) { 295 System.out.printf("Expected NullPointerException for " 296 + "scalar: %s, %s%n", scalarBytes, e.getMessage()); 297 continue; 298 } 299 throw new RuntimeException(e); 300 } catch (InvalidKeySpecException e) { 301 if (scalarBytes.length != validLen) { 302 System.out.printf("Expected InvalidKeySpecException for " 303 + "scalar length %s and curve %s: %s%n", 304 scalarBytes.length, curve, e.getMessage()); 305 continue; 306 } 307 throw new RuntimeException(e); 308 } 309 } 310 for (BigInteger coordinate : new BigInteger[]{null, BigInteger.ZERO, 311 BigInteger.ONE, new BigInteger("2").pow(255), 312 new BigInteger("2").pow(448)}) { 313 try { 314 KeySpec publicSpec = new XECPublicKeySpec(spec, coordinate); 315 kf.generatePublic(publicSpec); 316 } catch (NullPointerException e) { 317 if (coordinate == null) { 318 System.out.printf("Expected NullPointerException for " 319 + "coordinate : %s, %s%n", coordinate, 320 e.getMessage()); 321 continue; 322 } 323 throw new RuntimeException(e); 324 } 325 } 326 } 327 328 private static void testInCompatibleSpec(String provider, 329 String kpgAlgo, String curve) throws Exception { 330 331 int validLen = curve.equalsIgnoreCase("X448") ? 56 : 32; 332 NamedParameterSpec spec = new NamedParameterSpec(curve); 333 KeyFactory kf = KeyFactory.getInstance(kpgAlgo, provider); 334 KeySpec privateSpec = new XECPrivateKeySpec(spec, new byte[validLen]); 335 KeySpec publicSpec = new XECPublicKeySpec(spec, BigInteger.ONE); 336 try { 337 kf.generatePrivate(publicSpec); 338 throw new RuntimeException( 339 "testInCompatibleSpec should fail but passed."); 340 } catch (InvalidKeySpecException e) { 341 System.out.printf("Expected XECPublicKeySpec to XECPrivateKeySpec :" 342 + " %s%n", e.getMessage()); 343 } 344 try { 345 kf.generatePublic(privateSpec); 346 throw new RuntimeException( 347 "testInCompatibleSpec should fail but passed."); 348 } catch (InvalidKeySpecException e) { 349 System.out.printf("Expected XECPrivateKeySpec to XECPublicKeySpec :" 350 + " %s%n", e.getMessage()); 351 } 352 } 353 354 /** 355 * Perform KeyAgreement operation. 356 */ 357 private static void startKeyAgreement(String provider, String kaAlgo, 358 String kpgAlgo, int keySize) throws Exception { 359 360 KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgAlgo, provider); 361 kpg.initialize(keySize); 362 KeyPair kp = kpg.generateKeyPair(); 363 KeyAgreement ka = KeyAgreement.getInstance(kaAlgo, provider); 364 ka.init(kp.getPrivate()); 365 ka.doPhase(kp.getPublic(), true); 366 ka.generateSecret(); 367 } 368 369 private static byte[] modifyEncoded(byte[] encoded) { 370 371 byte[] copy = Arrays.copyOf(encoded, encoded.length); 372 for (int i = 0; i < copy.length; i++) { 373 copy[i] = (byte) ~copy[i]; 374 } 375 return copy; 376 } 377 378 private static String byteArrayToHexString(byte[] arr) { 379 380 StringBuilder result = new StringBuilder(); 381 for (int i = 0; i < arr.length; ++i) { 382 byte curVal = arr[i]; 383 result.append(Character.forDigit(curVal >> 4 & 0xF, 16)); 384 result.append(Character.forDigit(curVal & 0xF, 16)); 385 } 386 return result.toString(); 387 } 388 389 /** 390 * Select invalid key sizes for different Key generation algorithms. 391 */ 392 private static int[] selectInvalidKeylength(String kpgInit) { 393 394 int[] keySize = new int[]{}; 395 switch (kpgInit) { 396 case "DiffieHellman": 397 keySize = new int[]{256, 513, 8200}; 398 break; 399 case "EC": 400 keySize = new int[]{100, 300}; 401 break; 402 case "X25519": 403 keySize = new int[]{100, 300}; 404 break; 405 case "X448": 406 keySize = new int[]{100, 500}; 407 break; 408 default: 409 throw new RuntimeException("Invalid Algo name " + kpgInit); 410 } 411 return keySize; 412 } 413 }