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