1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package libcore.java.security; 18 19 import java.io.ByteArrayInputStream; 20 import java.io.ByteArrayOutputStream; 21 import java.io.ObjectInputStream; 22 import java.io.ObjectOutputStream; 23 import java.math.BigInteger; 24 import java.security.Key; 25 import java.security.KeyFactory; 26 import java.security.KeyPair; 27 import java.security.KeyPairGenerator; 28 import java.security.PrivateKey; 29 import java.security.Provider; 30 import java.security.Provider.Service; 31 import java.security.PublicKey; 32 import java.security.SecureRandom; 33 import java.security.Security; 34 import java.security.interfaces.DSAParams; 35 import java.security.interfaces.DSAPrivateKey; 36 import java.security.interfaces.DSAPublicKey; 37 import java.security.interfaces.ECPrivateKey; 38 import java.security.spec.AlgorithmParameterSpec; 39 import java.security.spec.DSAParameterSpec; 40 import java.security.spec.ECGenParameterSpec; 41 import java.security.spec.ECParameterSpec; 42 import java.security.spec.PKCS8EncodedKeySpec; 43 import java.security.spec.X509EncodedKeySpec; 44 import java.util.ArrayList; 45 import java.util.Arrays; 46 import java.util.HashMap; 47 import java.util.List; 48 import java.util.Locale; 49 import java.util.Map; 50 import java.util.Set; 51 import javax.crypto.interfaces.DHPrivateKey; 52 import javax.crypto.interfaces.DHPublicKey; 53 import javax.crypto.spec.DHParameterSpec; 54 55 import junit.framework.TestCase; 56 57 import dalvik.system.VMRuntime; 58 import sun.security.jca.Providers; 59 60 public class KeyPairGeneratorTest extends TestCase { 61 62 private List<Provider> providers = new ArrayList<Provider>(); 63 64 @Override 65 public void setUp() throws Exception { 66 super.setUp(); 67 // Allow access to deprecated BC algorithms in this test, so we can ensure they 68 // continue to work 69 Providers.setMaximumAllowableApiLevelForBcDeprecation( 70 VMRuntime.getRuntime().getTargetSdkVersion()); 71 72 Provider[] providers = Security.getProviders(); 73 for (Provider p : providers) { 74 // Do not test AndroidKeyStore Provider. It does not accept vanilla public keys for 75 // signature verification. It's OKish not to test here because it's tested by 76 // cts/tests/tests/keystore. 77 if (!p.getName().startsWith("AndroidKeyStore")) { 78 this.providers.add(p); 79 } 80 } 81 } 82 83 @Override 84 public void tearDown() throws Exception { 85 providers.clear(); 86 Providers.setMaximumAllowableApiLevelForBcDeprecation( 87 Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION); 88 super.tearDown(); 89 } 90 91 public void test_providerCount() { 92 // We expect there to be at least one provider. 93 assertTrue(providers.size() > 0); 94 // If this fails remember to add _provider methods below. This test is sharded because it 95 // takes a long time to execute. 96 assertTrue(providers.size() < 10); 97 } 98 99 public void test_getInstance_provider0() throws Exception { 100 test_getInstance(0); 101 } 102 103 public void test_getInstance_provider1() throws Exception { 104 test_getInstance(1); 105 } 106 107 public void test_getInstance_provider2() throws Exception { 108 test_getInstance(2); 109 } 110 111 public void test_getInstance_provider3() throws Exception { 112 test_getInstance(3); 113 } 114 115 public void test_getInstance_provider4() throws Exception { 116 test_getInstance(4); 117 } 118 119 public void test_getInstance_provider5() throws Exception { 120 test_getInstance(5); 121 } 122 123 public void test_getInstance_provider6() throws Exception { 124 test_getInstance(6); 125 } 126 127 public void test_getInstance_provider7() throws Exception { 128 test_getInstance(7); 129 } 130 131 public void test_getInstance_provider8() throws Exception { 132 test_getInstance(8); 133 } 134 135 public void test_getInstance_provider9() throws Exception { 136 test_getInstance(9); 137 } 138 139 private void test_getInstance(int providerIndex) throws Exception { 140 if (providerIndex >= providers.size()) { 141 // Providers can be added by vendors and other tests. We do not 142 // specify a fixed number and silenty pass if the provider at the 143 // specified index does not exist. 144 return; 145 } 146 147 Provider provider = providers.get(providerIndex); 148 Set<Provider.Service> services = provider.getServices(); 149 for (Provider.Service service : services) { 150 String type = service.getType(); 151 if (!type.equals("KeyPairGenerator")) { 152 continue; 153 } 154 String algorithm = service.getAlgorithm(); 155 AlgorithmParameterSpec params = null; 156 157 if ("DH".equals(algorithm)) { 158 params = getDHParams(); 159 } 160 161 try { 162 // KeyPairGenerator.getInstance(String) 163 KeyPairGenerator kpg1 = KeyPairGenerator.getInstance(algorithm); 164 assertEquals(algorithm, kpg1.getAlgorithm()); 165 if (params != null) { 166 kpg1.initialize(params); 167 } 168 test_KeyPairGenerator(kpg1); 169 170 // KeyPairGenerator.getInstance(String, Provider) 171 KeyPairGenerator kpg2 = KeyPairGenerator.getInstance(algorithm, provider); 172 assertEquals(algorithm, kpg2.getAlgorithm()); 173 assertEquals(provider, kpg2.getProvider()); 174 if (params != null) { 175 kpg2.initialize(params); 176 } 177 test_KeyPairGenerator(kpg2); 178 179 // KeyPairGenerator.getInstance(String, String) 180 KeyPairGenerator kpg3 = KeyPairGenerator.getInstance(algorithm, 181 provider.getName()); 182 assertEquals(algorithm, kpg3.getAlgorithm()); 183 assertEquals(provider, kpg3.getProvider()); 184 if (params != null) { 185 kpg3.initialize(params); 186 } 187 test_KeyPairGenerator(kpg3); 188 } catch (Exception e) { 189 throw new Exception("Problem testing KeyPairGenerator." + algorithm, e); 190 } 191 } 192 } 193 194 private static final Map<String, List<Integer>> KEY_SIZES 195 = new HashMap<String, List<Integer>>(); 196 private static void putKeySize(String algorithm, int keySize) { 197 algorithm = algorithm.toUpperCase(); 198 List<Integer> keySizes = KEY_SIZES.get(algorithm); 199 if (keySizes == null) { 200 keySizes = new ArrayList<Integer>(); 201 KEY_SIZES.put(algorithm, keySizes); 202 } 203 keySizes.add(keySize); 204 } 205 private static List<Integer> getKeySizes(String algorithm) throws Exception { 206 algorithm = algorithm.toUpperCase(); 207 List<Integer> keySizes = KEY_SIZES.get(algorithm); 208 if (keySizes == null) { 209 throw new Exception("Unknown key sizes for KeyPairGenerator." + algorithm); 210 } 211 return keySizes; 212 } 213 static { 214 putKeySize("DSA", 512); 215 putKeySize("DSA", 512+64); 216 putKeySize("DSA", 1024); 217 putKeySize("RSA", 512); 218 putKeySize("DH", 512); 219 putKeySize("DH", 512+64); 220 putKeySize("DH", 1024); 221 putKeySize("DiffieHellman", 512); 222 putKeySize("DiffieHellman", 512+64); 223 putKeySize("DiffieHellman", 1024); 224 putKeySize("EC", 224); 225 putKeySize("EC", 256); 226 putKeySize("EC", 384); 227 putKeySize("EC", 521); 228 } 229 230 /** Elliptic Curve Crypto named curves that should be supported. */ 231 private static final String[] EC_NAMED_CURVES = { 232 // NIST P-256 aka SECG secp256r1 aka ANSI X9.62 prime256v1 233 "secp256r1", "prime256v1", 234 // NIST P-521 aka SECG secp521r1 235 "secp521r1", 236 }; 237 238 private void test_KeyPairGenerator(KeyPairGenerator kpg) throws Exception { 239 // without a call to initialize 240 test_KeyPair(kpg, kpg.genKeyPair()); 241 test_KeyPair(kpg, kpg.generateKeyPair()); 242 243 String algorithm = kpg.getAlgorithm(); 244 245 // TODO: detect if we're running in vogar and run the full test 246 if ("DH".equals(algorithm)) { 247 // Disabled because this takes too long on devices. 248 // TODO: Re-enable DH test. http://b/5513723. 249 return; 250 } 251 252 List<Integer> keySizes = getKeySizes(algorithm); 253 for (int keySize : keySizes) { 254 kpg.initialize(keySize); 255 test_KeyPair(kpg, kpg.genKeyPair()); 256 test_KeyPair(kpg, kpg.generateKeyPair()); 257 258 kpg.initialize(keySize, (SecureRandom) null); 259 test_KeyPair(kpg, kpg.genKeyPair()); 260 test_KeyPair(kpg, kpg.generateKeyPair()); 261 262 kpg.initialize(keySize, new SecureRandom()); 263 test_KeyPair(kpg, kpg.genKeyPair()); 264 test_KeyPair(kpg, kpg.generateKeyPair()); 265 } 266 267 if (("EC".equals(algorithm)) || ("ECDH".equals(algorithm)) 268 || ("ECDSA".equals(algorithm))) { 269 for (String curveName : EC_NAMED_CURVES) { 270 kpg.initialize(new ECGenParameterSpec(curveName)); 271 test_KeyPair(kpg, kpg.genKeyPair()); 272 test_KeyPair(kpg, kpg.generateKeyPair()); 273 274 kpg.initialize(new ECGenParameterSpec(curveName), (SecureRandom) null); 275 test_KeyPair(kpg, kpg.genKeyPair()); 276 test_KeyPair(kpg, kpg.generateKeyPair()); 277 278 kpg.initialize(new ECGenParameterSpec(curveName), new SecureRandom()); 279 test_KeyPair(kpg, kpg.genKeyPair()); 280 test_KeyPair(kpg, kpg.generateKeyPair()); 281 } 282 } 283 } 284 285 private void test_KeyPair(KeyPairGenerator kpg, KeyPair kp) throws Exception { 286 assertNotNull(kp); 287 test_Key(kpg, kp.getPrivate()); 288 test_Key(kpg, kp.getPublic()); 289 } 290 291 private void test_Key(KeyPairGenerator kpg, Key k) throws Exception { 292 String expectedAlgorithm = kpg.getAlgorithm().toUpperCase(Locale.ROOT); 293 if (StandardNames.IS_RI && expectedAlgorithm.equals("DIFFIEHELLMAN")) { 294 expectedAlgorithm = "DH"; 295 } 296 assertEquals(expectedAlgorithm, k.getAlgorithm().toUpperCase()); 297 if (expectedAlgorithm.equals("DH")) { 298 if (k instanceof DHPublicKey) { 299 DHPublicKey dhPub = (DHPublicKey) k; 300 assertEquals(dhPub.getParams().getP(), getDHParams().getP()); 301 } else if (k instanceof DHPrivateKey) { 302 DHPrivateKey dhPriv = (DHPrivateKey) k; 303 assertEquals(dhPriv.getParams().getP(), getDHParams().getP()); 304 } else { 305 fail("not a public or private key!?"); 306 } 307 } 308 assertNotNull(k.getEncoded()); 309 assertNotNull(k.getFormat()); 310 311 // Test serialization 312 { 313 ByteArrayOutputStream baos = new ByteArrayOutputStream(16384); 314 ObjectOutputStream oos = new ObjectOutputStream(baos); 315 oos.writeObject(k); 316 317 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); 318 ObjectInputStream ois = new ObjectInputStream(bais); 319 Key inflatedKey = (Key) ois.readObject(); 320 321 assertEquals(k, inflatedKey); 322 } 323 324 test_KeyWithAllKeyFactories(k); 325 } 326 327 private void test_KeyWithAllKeyFactories(Key k) throws Exception { 328 byte[] encoded = k.getEncoded(); 329 330 String keyAlgo = k.getAlgorithm(); 331 for (Provider p : providers) { 332 Set<Provider.Service> services = p.getServices(); 333 for (Provider.Service service : services) { 334 if (!"KeyFactory".equals(service.getType())) { 335 continue; 336 } 337 if (!service.getAlgorithm().equals(keyAlgo)) { 338 continue; 339 } 340 341 if ("PKCS#8".equals(k.getFormat())) { 342 PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(encoded); 343 KeyFactory kf = KeyFactory.getInstance(k.getAlgorithm(), p); 344 PrivateKey privKey = kf.generatePrivate(spec); 345 assertNotNull(k.getAlgorithm() + ", provider=" + p.getName(), privKey); 346 347 /* 348 * EC keys are unique because they can have explicit parameters or a curve 349 * name. Check them specially so this test can continue to function. 350 */ 351 if (k instanceof ECPrivateKey) { 352 assertECPrivateKeyEquals((ECPrivateKey) k, (ECPrivateKey) privKey); 353 } else { 354 assertEquals(k.getAlgorithm() + ", provider=" + p.getName(), 355 Arrays.toString(encoded), 356 Arrays.toString(privKey.getEncoded())); 357 } 358 } else if ("X.509".equals(k.getFormat())) { 359 X509EncodedKeySpec spec = new X509EncodedKeySpec(encoded); 360 KeyFactory kf = KeyFactory.getInstance(k.getAlgorithm(), p); 361 PublicKey pubKey = kf.generatePublic(spec); 362 assertNotNull(pubKey); 363 assertTrue(Arrays.equals(encoded, pubKey.getEncoded())); 364 } 365 } 366 } 367 } 368 369 private static void assertECPrivateKeyEquals(ECPrivateKey expected, ECPrivateKey actual) { 370 assertEquals(expected.getS(), actual.getS()); 371 assertECParametersEquals(expected.getParams(), actual.getParams()); 372 } 373 374 private static void assertECParametersEquals(ECParameterSpec expected, ECParameterSpec actual) { 375 assertEquals(expected.getCurve(), actual.getCurve()); 376 assertEquals(expected.getGenerator(), actual.getGenerator()); 377 assertEquals(expected.getOrder(), actual.getOrder()); 378 assertEquals(expected.getCofactor(), actual.getCofactor()); 379 } 380 381 /** 382 * DH parameters pre-generated so that the test doesn't take too long. 383 * These parameters were generated with: 384 * 385 * openssl gendh 512 | openssl dhparams -C 386 */ 387 private static DHParameterSpec getDHParams() { 388 BigInteger p = new BigInteger("E7AB1768BD75CD24700960FFA32D3F1557344E587101237532CC641646ED7A7C104743377F6D46251698B665CE2A6CBAB6714C2569A7D2CA22C0CF03FA40AC93", 16); 389 BigInteger g = new BigInteger("02", 16); 390 return new DHParameterSpec(p, g, 512); 391 } 392 393 private static final BigInteger DSA_P = new BigInteger(new byte[] { 394 (byte) 0x00, (byte) 0x9e, (byte) 0x61, (byte) 0xc2, (byte) 0x89, (byte) 0xef, (byte) 0x77, (byte) 0xa9, 395 (byte) 0x4e, (byte) 0x13, (byte) 0x67, (byte) 0x64, (byte) 0x1f, (byte) 0x09, (byte) 0x01, (byte) 0xfe, 396 (byte) 0x24, (byte) 0x13, (byte) 0x53, (byte) 0xe0, (byte) 0xb7, (byte) 0x90, (byte) 0xa8, (byte) 0x4e, 397 (byte) 0x76, (byte) 0xfe, (byte) 0x89, (byte) 0x82, (byte) 0x7f, (byte) 0x7a, (byte) 0xc5, (byte) 0x3c, 398 (byte) 0x4e, (byte) 0x0c, (byte) 0x20, (byte) 0x55, (byte) 0x30, (byte) 0x95, (byte) 0x42, (byte) 0x85, 399 (byte) 0xe1, (byte) 0x40, (byte) 0x7d, (byte) 0x27, (byte) 0x8f, (byte) 0x07, (byte) 0x0d, (byte) 0xe8, 400 (byte) 0xdc, (byte) 0x99, (byte) 0xef, (byte) 0xb3, (byte) 0x07, (byte) 0x94, (byte) 0x34, (byte) 0xd6, 401 (byte) 0x7c, (byte) 0xff, (byte) 0x9c, (byte) 0xbe, (byte) 0x69, (byte) 0xd3, (byte) 0xeb, (byte) 0x44, 402 (byte) 0x37, (byte) 0x50, (byte) 0xef, (byte) 0x49, (byte) 0xf8, (byte) 0xe2, (byte) 0x5b, (byte) 0xd8, 403 (byte) 0xd1, (byte) 0x10, (byte) 0x84, (byte) 0x97, (byte) 0xea, (byte) 0xe3, (byte) 0xa5, (byte) 0x1c, 404 (byte) 0xc0, (byte) 0x4e, (byte) 0x69, (byte) 0xca, (byte) 0x70, (byte) 0x3d, (byte) 0x78, (byte) 0xb9, 405 (byte) 0x16, (byte) 0xe5, (byte) 0xfe, (byte) 0x61, (byte) 0x5d, (byte) 0x8a, (byte) 0x5a, (byte) 0xb3, 406 (byte) 0x2c, (byte) 0x61, (byte) 0xb6, (byte) 0x01, (byte) 0x3b, (byte) 0xd0, (byte) 0x01, (byte) 0x7c, 407 (byte) 0x32, (byte) 0x8d, (byte) 0xe1, (byte) 0xf3, (byte) 0x69, (byte) 0x0e, (byte) 0x8b, (byte) 0x58, 408 (byte) 0xc6, (byte) 0xcf, (byte) 0x00, (byte) 0x94, (byte) 0xf8, (byte) 0x49, (byte) 0x2a, (byte) 0x4b, 409 (byte) 0xea, (byte) 0xda, (byte) 0x00, (byte) 0xff, (byte) 0x4b, (byte) 0xd0, (byte) 0xbe, (byte) 0x40, 410 (byte) 0x23, 411 }); 412 413 private static final BigInteger DSA_Q = new BigInteger(new byte[] { 414 (byte) 0x00, (byte) 0xbf, (byte) 0xee, (byte) 0xaa, (byte) 0x0f, (byte) 0x12, (byte) 0x34, (byte) 0x50, 415 (byte) 0x72, (byte) 0xf8, (byte) 0x60, (byte) 0x13, (byte) 0xd8, (byte) 0xf1, (byte) 0x41, (byte) 0x01, 416 (byte) 0x10, (byte) 0xa5, (byte) 0x2f, (byte) 0x57, (byte) 0x5f, 417 }); 418 419 private static final BigInteger DSA_G = new BigInteger(new byte[] { 420 (byte) 0x77, (byte) 0xd4, (byte) 0x7a, (byte) 0x12, (byte) 0xcc, (byte) 0x81, (byte) 0x7e, (byte) 0x7e, 421 (byte) 0xeb, (byte) 0x3a, (byte) 0xfb, (byte) 0xe6, (byte) 0x86, (byte) 0x6d, (byte) 0x5a, (byte) 0x10, 422 (byte) 0x1d, (byte) 0xad, (byte) 0xa9, (byte) 0x4f, (byte) 0xb9, (byte) 0x03, (byte) 0x5d, (byte) 0x21, 423 (byte) 0x1a, (byte) 0xe4, (byte) 0x30, (byte) 0x95, (byte) 0x75, (byte) 0x8e, (byte) 0xcd, (byte) 0x5e, 424 (byte) 0xd1, (byte) 0xbd, (byte) 0x0a, (byte) 0x45, (byte) 0xee, (byte) 0xe7, (byte) 0xf7, (byte) 0x6b, 425 (byte) 0x65, (byte) 0x02, (byte) 0x60, (byte) 0xd0, (byte) 0x2e, (byte) 0xaf, (byte) 0x3d, (byte) 0xbc, 426 (byte) 0x07, (byte) 0xdd, (byte) 0x2b, (byte) 0x8e, (byte) 0x33, (byte) 0xc0, (byte) 0x93, (byte) 0x80, 427 (byte) 0xd9, (byte) 0x2b, (byte) 0xa7, (byte) 0x71, (byte) 0x57, (byte) 0x76, (byte) 0xbc, (byte) 0x8e, 428 (byte) 0xb9, (byte) 0xe0, (byte) 0xd7, (byte) 0xf4, (byte) 0x23, (byte) 0x8d, (byte) 0x41, (byte) 0x1a, 429 (byte) 0x97, (byte) 0x4f, (byte) 0x2c, (byte) 0x1b, (byte) 0xd5, (byte) 0x4b, (byte) 0x66, (byte) 0xe8, 430 (byte) 0xfa, (byte) 0xd2, (byte) 0x50, (byte) 0x0d, (byte) 0x17, (byte) 0xab, (byte) 0x34, (byte) 0x31, 431 (byte) 0x3d, (byte) 0xa4, (byte) 0x88, (byte) 0xd8, (byte) 0x8e, (byte) 0xa8, (byte) 0xa7, (byte) 0x6e, 432 (byte) 0x17, (byte) 0x03, (byte) 0xb7, (byte) 0x0f, (byte) 0x68, (byte) 0x7c, (byte) 0x64, (byte) 0x7b, 433 (byte) 0x92, (byte) 0xb8, (byte) 0x63, (byte) 0xe4, (byte) 0x9a, (byte) 0x67, (byte) 0x18, (byte) 0x81, 434 (byte) 0x27, (byte) 0xd4, (byte) 0x0b, (byte) 0x13, (byte) 0x48, (byte) 0xd3, (byte) 0x7d, (byte) 0x4e, 435 (byte) 0xf6, (byte) 0xa8, (byte) 0x8f, (byte) 0x56, (byte) 0x17, (byte) 0x2d, (byte) 0x08, (byte) 0x51, 436 }); 437 438 public void testDSAGeneratorWithParams() throws Exception { 439 final DSAParameterSpec dsaSpec = new DSAParameterSpec(DSA_P, DSA_Q, DSA_G); 440 441 final Provider[] providers = Security.getProviders(); 442 for (final Provider p : providers) { 443 Service s = p.getService("KeyPairGenerator", "DSA"); 444 if (s == null) { 445 continue; 446 } 447 448 final KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA", p); 449 kpg.initialize(dsaSpec); 450 KeyPair pair = kpg.generateKeyPair(); 451 DSAPrivateKey privKey = (DSAPrivateKey) pair.getPrivate(); 452 DSAPublicKey pubKey = (DSAPublicKey) pair.getPublic(); 453 454 DSAParams actualParams = privKey.getParams(); 455 assertNotNull("DSA params should not be null", actualParams); 456 457 assertEquals("DSA P should be the same as supplied with provider " + p.getName(), 458 DSA_P, actualParams.getP()); 459 assertEquals("DSA Q should be the same as supplied with provider " + p.getName(), 460 DSA_Q, actualParams.getQ()); 461 assertEquals("DSA G should be the same as supplied with provider " + p.getName(), 462 DSA_G, actualParams.getG()); 463 464 actualParams = pubKey.getParams(); 465 assertNotNull("DSA params should not be null", actualParams); 466 467 assertEquals("DSA P should be the same as supplied with provider " + p.getName(), 468 DSA_P, actualParams.getP()); 469 assertEquals("DSA Q should be the same as supplied with provider " + p.getName(), 470 DSA_Q, actualParams.getQ()); 471 assertEquals("DSA G should be the same as supplied with provider " + p.getName(), 472 DSA_G, actualParams.getG()); 473 } 474 } 475 } 476