1 /* 2 * Copyright (C) 2015 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 android.keystore.cts; 18 19 import android.security.keystore.KeyGenParameterSpec; 20 import android.security.keystore.KeyInfo; 21 import android.security.keystore.KeyProperties; 22 import android.test.AndroidTestCase; 23 import android.test.MoreAsserts; 24 25 import android.keystore.cts.R; 26 27 import java.io.InputStream; 28 import java.security.InvalidKeyException; 29 import java.security.KeyFactory; 30 import java.security.KeyPair; 31 import java.security.KeyPairGenerator; 32 import java.security.NoSuchAlgorithmException; 33 import java.security.NoSuchProviderException; 34 import java.security.PrivateKey; 35 import java.security.Provider; 36 import java.security.Security; 37 import java.security.interfaces.ECPublicKey; 38 import java.security.interfaces.RSAPublicKey; 39 import java.security.spec.ECPrivateKeySpec; 40 import java.security.spec.ECPublicKeySpec; 41 import java.security.spec.InvalidKeySpecException; 42 import java.security.spec.KeySpec; 43 import java.security.spec.PKCS8EncodedKeySpec; 44 import java.security.spec.RSAPrivateKeySpec; 45 import java.security.spec.RSAPublicKeySpec; 46 import java.security.spec.X509EncodedKeySpec; 47 import java.security.Provider.Service; 48 import java.security.PublicKey; 49 import java.util.ArrayList; 50 import java.util.Arrays; 51 import java.util.Date; 52 import java.util.HashSet; 53 import java.util.List; 54 import java.util.Locale; 55 import java.util.Set; 56 57 import javax.crypto.SecretKey; 58 import javax.crypto.spec.SecretKeySpec; 59 60 public class KeyFactoryTest extends AndroidTestCase { 61 private static final String EXPECTED_PROVIDER_NAME = TestUtils.EXPECTED_PROVIDER_NAME; 62 63 private static final String[] EXPECTED_ALGORITHMS = { 64 "EC", 65 "RSA", 66 }; 67 68 public void testAlgorithmList() { 69 // Assert that Android Keystore Provider exposes exactly the expected KeyFactory algorithms. 70 // We don't care whether the algorithms are exposed via aliases, as long as canonical names 71 // of algorithms are accepted. If the Provider exposes extraneous algorithms, it'll be 72 // caught because it'll have to expose at least one Service for such an algorithm, and this 73 // Service's algorithm will not be in the expected set. 74 75 Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME); 76 Set<Service> services = provider.getServices(); 77 Set<String> actualAlgsLowerCase = new HashSet<String>(); 78 Set<String> expectedAlgsLowerCase = new HashSet<String>( 79 Arrays.asList(TestUtils.toLowerCase(EXPECTED_ALGORITHMS))); 80 for (Service service : services) { 81 if ("KeyFactory".equalsIgnoreCase(service.getType())) { 82 String algLowerCase = service.getAlgorithm().toLowerCase(Locale.US); 83 actualAlgsLowerCase.add(algLowerCase); 84 } 85 } 86 87 TestUtils.assertContentsInAnyOrder(actualAlgsLowerCase, 88 expectedAlgsLowerCase.toArray(new String[0])); 89 } 90 91 public void testGetKeySpecWithKeystorePrivateKeyAndKeyInfoReflectsAllAuthorizations() 92 throws Exception { 93 Date keyValidityStart = new Date(System.currentTimeMillis() - TestUtils.DAY_IN_MILLIS); 94 Date keyValidityForOriginationEnd = 95 new Date(System.currentTimeMillis() + TestUtils.DAY_IN_MILLIS); 96 Date keyValidityForConsumptionEnd = 97 new Date(System.currentTimeMillis() + 3 * TestUtils.DAY_IN_MILLIS); 98 for (String algorithm : EXPECTED_ALGORITHMS) { 99 try { 100 String[] blockModes = new String[] {KeyProperties.BLOCK_MODE_ECB}; 101 String[] encryptionPaddings = 102 new String[] {KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1, 103 KeyProperties.ENCRYPTION_PADDING_RSA_OAEP}; 104 String[] digests = new String[] {KeyProperties.DIGEST_SHA1, 105 KeyProperties.DIGEST_SHA224, 106 KeyProperties.DIGEST_SHA384, 107 KeyProperties.DIGEST_SHA512}; 108 int purposes = KeyProperties.PURPOSE_DECRYPT | KeyProperties.PURPOSE_SIGN; 109 KeyPairGenerator keyGenerator = 110 KeyPairGenerator.getInstance(algorithm, EXPECTED_PROVIDER_NAME); 111 keyGenerator.initialize(new KeyGenParameterSpec.Builder("test1", purposes) 112 .setBlockModes(blockModes) 113 .setEncryptionPaddings(encryptionPaddings) 114 .setDigests(digests) 115 .setKeyValidityStart(keyValidityStart) 116 .setKeyValidityForOriginationEnd(keyValidityForOriginationEnd) 117 .setKeyValidityForConsumptionEnd(keyValidityForConsumptionEnd) 118 .build()); 119 KeyPair keyPair = keyGenerator.generateKeyPair(); 120 KeyFactory keyFactory = getKeyFactory(algorithm); 121 KeyInfo keyInfo = keyFactory.getKeySpec(keyPair.getPrivate(), KeyInfo.class); 122 assertEquals("test1", keyInfo.getKeystoreAlias()); 123 assertEquals(purposes, keyInfo.getPurposes()); 124 TestUtils.assertContentsInAnyOrder( 125 Arrays.asList(keyInfo.getBlockModes()), blockModes); 126 127 List<String> actualEncryptionPaddings = 128 new ArrayList<String>(Arrays.asList(keyInfo.getEncryptionPaddings())); 129 // Keystore may have added ENCRYPTION_PADDING_NONE to allow software padding. 130 actualEncryptionPaddings.remove(KeyProperties.ENCRYPTION_PADDING_NONE); 131 TestUtils.assertContentsInAnyOrder( 132 actualEncryptionPaddings, encryptionPaddings); 133 134 List<String> actualDigests = 135 new ArrayList<String>(Arrays.asList(keyInfo.getDigests())); 136 // Keystore may have added DIGEST_NONE to allow software digesting. 137 actualDigests.remove(KeyProperties.DIGEST_NONE); 138 TestUtils.assertContentsInAnyOrder(actualDigests, digests); 139 140 MoreAsserts.assertEmpty(Arrays.asList(keyInfo.getSignaturePaddings())); 141 assertEquals(keyValidityStart, keyInfo.getKeyValidityStart()); 142 assertEquals(keyValidityForOriginationEnd, 143 keyInfo.getKeyValidityForOriginationEnd()); 144 assertEquals(keyValidityForConsumptionEnd, 145 keyInfo.getKeyValidityForConsumptionEnd()); 146 assertFalse(keyInfo.isUserAuthenticationRequired()); 147 assertFalse(keyInfo.isUserAuthenticationRequirementEnforcedBySecureHardware()); 148 } catch (Throwable e) { 149 throw new RuntimeException("Failed for " + algorithm, e); 150 } 151 } 152 } 153 154 public void testGetKeySpecWithKeystorePublicKeyRejectsKeyInfo() 155 throws Exception { 156 for (String algorithm : EXPECTED_ALGORITHMS) { 157 try { 158 KeyPairGenerator keyGenerator = 159 KeyPairGenerator.getInstance(algorithm, EXPECTED_PROVIDER_NAME); 160 keyGenerator.initialize(new KeyGenParameterSpec.Builder("test1", 0).build()); 161 KeyPair keyPair = keyGenerator.generateKeyPair(); 162 KeyFactory keyFactory = getKeyFactory(algorithm); 163 try { 164 keyFactory.getKeySpec(keyPair.getPublic(), KeyInfo.class); 165 fail(); 166 } catch (InvalidKeySpecException expected) {} 167 } catch (Throwable e) { 168 throw new RuntimeException("Failed for " + algorithm, e); 169 } 170 } 171 } 172 173 public void testGetKeySpecWithKeystorePrivateKeyRejectsTransparentKeySpecAndEncodedKeySpec() 174 throws Exception { 175 for (String algorithm : EXPECTED_ALGORITHMS) { 176 try { 177 Class<? extends KeySpec> transparentKeySpecClass; 178 if ("EC".equalsIgnoreCase(algorithm)) { 179 transparentKeySpecClass = ECPrivateKeySpec.class; 180 } else if ("RSA".equalsIgnoreCase(algorithm)) { 181 transparentKeySpecClass = RSAPrivateKeySpec.class; 182 } else { 183 throw new RuntimeException("Unsupported key algorithm: " + algorithm); 184 } 185 186 KeyPairGenerator keyGenerator = 187 KeyPairGenerator.getInstance(algorithm, EXPECTED_PROVIDER_NAME); 188 keyGenerator.initialize(new KeyGenParameterSpec.Builder("test1", 0).build()); 189 KeyPair keyPair = keyGenerator.generateKeyPair(); 190 191 KeyFactory keyFactory = getKeyFactory(algorithm); 192 try { 193 keyFactory.getKeySpec(keyPair.getPrivate(), transparentKeySpecClass); 194 fail(); 195 } catch (InvalidKeySpecException expected) {} 196 197 try { 198 keyFactory.getKeySpec(keyPair.getPrivate(), PKCS8EncodedKeySpec.class); 199 fail(); 200 } catch (InvalidKeySpecException expected) {} 201 } catch (Throwable e) { 202 throw new RuntimeException("Failed for " + algorithm, e); 203 } 204 } 205 } 206 207 public void testGetKeySpecWithKeystorePublicKeyAcceptsX509EncodedKeySpec() 208 throws Exception { 209 for (String algorithm : EXPECTED_ALGORITHMS) { 210 try { 211 KeyPairGenerator keyGenerator = 212 KeyPairGenerator.getInstance(algorithm, EXPECTED_PROVIDER_NAME); 213 keyGenerator.initialize(new KeyGenParameterSpec.Builder("test1", 0).build()); 214 KeyPair keyPair = keyGenerator.generateKeyPair(); 215 PublicKey publicKey = keyPair.getPublic(); 216 217 KeyFactory keyFactory = getKeyFactory(algorithm); 218 X509EncodedKeySpec x509EncodedSpec = 219 keyFactory.getKeySpec(publicKey, X509EncodedKeySpec.class); 220 MoreAsserts.assertEquals(publicKey.getEncoded(), x509EncodedSpec.getEncoded()); 221 } catch (Throwable e) { 222 throw new RuntimeException("Failed for " + algorithm, e); 223 } 224 } 225 } 226 227 public void testGetKeySpecWithKeystorePublicKeyAcceptsTransparentKeySpec() 228 throws Exception { 229 for (String algorithm : EXPECTED_ALGORITHMS) { 230 try { 231 KeyPairGenerator keyGenerator = 232 KeyPairGenerator.getInstance(algorithm, EXPECTED_PROVIDER_NAME); 233 keyGenerator.initialize(new KeyGenParameterSpec.Builder("test1", 0).build()); 234 KeyPair keyPair = keyGenerator.generateKeyPair(); 235 PublicKey publicKey = keyPair.getPublic(); 236 237 KeyFactory keyFactory = getKeyFactory(algorithm); 238 if ("EC".equalsIgnoreCase(algorithm)) { 239 ECPublicKey ecPublicKey = (ECPublicKey) publicKey; 240 ECPublicKeySpec spec = 241 keyFactory.getKeySpec(publicKey, ECPublicKeySpec.class); 242 assertEquals(ecPublicKey.getW(), spec.getW()); 243 TestUtils.assertECParameterSpecEqualsIgnoreSeedIfNotPresent( 244 ecPublicKey.getParams(), spec.getParams()); 245 } else if ("RSA".equalsIgnoreCase(algorithm)) { 246 RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey; 247 RSAPublicKeySpec spec = 248 keyFactory.getKeySpec(publicKey, RSAPublicKeySpec.class); 249 assertEquals(rsaPublicKey.getModulus(), spec.getModulus()); 250 assertEquals(rsaPublicKey.getPublicExponent(), spec.getPublicExponent()); 251 } else { 252 throw new RuntimeException("Unsupported key algorithm: " + algorithm); 253 } 254 } catch (Throwable e) { 255 throw new RuntimeException("Failed for " + algorithm, e); 256 } 257 } 258 } 259 260 public void testTranslateKeyWithNullKeyThrowsInvalidKeyException() throws Exception { 261 for (String algorithm : EXPECTED_ALGORITHMS) { 262 try { 263 KeyFactory keyFactory = getKeyFactory(algorithm); 264 try { 265 keyFactory.translateKey(null); 266 fail(); 267 } catch (InvalidKeyException expected) {} 268 } catch (Throwable e) { 269 throw new RuntimeException("Failed for " + algorithm, e); 270 } 271 } 272 } 273 274 public void testTranslateKeyRejectsNonAndroidKeystoreKeys() throws Exception { 275 for (String algorithm : EXPECTED_ALGORITHMS) { 276 try { 277 SecretKey key = new SecretKeySpec(new byte[16], algorithm); 278 KeyFactory keyFactory = getKeyFactory(algorithm); 279 try { 280 keyFactory.translateKey(key); 281 fail(); 282 } catch (InvalidKeyException expected) {} 283 } catch (Throwable e) { 284 throw new RuntimeException("Failed for " + algorithm, e); 285 } 286 } 287 } 288 289 public void testTranslateKeyAcceptsAndroidKeystoreKeys() throws Exception { 290 for (String algorithm : EXPECTED_ALGORITHMS) { 291 try { 292 KeyPairGenerator keyGenerator = 293 KeyPairGenerator.getInstance(algorithm, EXPECTED_PROVIDER_NAME); 294 keyGenerator.initialize(new KeyGenParameterSpec.Builder("test1", 0).build()); 295 KeyPair keyPair = keyGenerator.generateKeyPair(); 296 297 KeyFactory keyFactory = getKeyFactory(algorithm); 298 assertSame(keyPair.getPrivate(), keyFactory.translateKey(keyPair.getPrivate())); 299 assertSame(keyPair.getPublic(), keyFactory.translateKey(keyPair.getPublic())); 300 } catch (Throwable e) { 301 throw new RuntimeException("Failed for " + algorithm, e); 302 } 303 } 304 } 305 306 public void testGeneratePrivateWithNullSpecThrowsInvalidKeySpecException() throws Exception { 307 for (String algorithm : EXPECTED_ALGORITHMS) { 308 try { 309 KeyFactory keyFactory = getKeyFactory(algorithm); 310 try { 311 keyFactory.generatePrivate(null); 312 fail(); 313 } catch (InvalidKeySpecException expected) {} 314 } catch (Throwable e) { 315 throw new RuntimeException("Failed for " + algorithm, e); 316 } 317 } 318 } 319 320 public void testGeneratePublicWithNullSpecThrowsInvalidKeySpecException() throws Exception { 321 for (String algorithm : EXPECTED_ALGORITHMS) { 322 try { 323 KeyFactory keyFactory = getKeyFactory(algorithm); 324 try { 325 keyFactory.generatePublic(null); 326 fail(); 327 } catch (InvalidKeySpecException expected) {} 328 } catch (Throwable e) { 329 throw new RuntimeException("Failed for " + algorithm, e); 330 } 331 } 332 } 333 334 public void testGeneratePrivateRejectsPKCS8EncodedKeySpec() throws Exception { 335 for (String algorithm : EXPECTED_ALGORITHMS) { 336 int resId; 337 if ("EC".equalsIgnoreCase(algorithm)) { 338 resId = R.raw.ec_key1_pkcs8; 339 } else if ("RSA".equalsIgnoreCase(algorithm)) { 340 resId = R.raw.rsa_key2_pkcs8; 341 } else { 342 throw new RuntimeException("Unsupported key algorithm: " + algorithm); 343 } 344 345 byte[] pkcs8EncodedForm; 346 try (InputStream in = getContext().getResources().openRawResource(resId)) { 347 pkcs8EncodedForm = TestUtils.drain(in); 348 } 349 PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(pkcs8EncodedForm); 350 try { 351 KeyFactory keyFactory = getKeyFactory(algorithm); 352 try { 353 keyFactory.generatePrivate(spec); 354 fail(); 355 } catch (InvalidKeySpecException expected) {} 356 } catch (Throwable e) { 357 throw new RuntimeException("Failed for " + algorithm, e); 358 } 359 } 360 } 361 362 public void testGeneratePublicRejectsX509EncodedKeySpec() throws Exception { 363 for (String algorithm : EXPECTED_ALGORITHMS) { 364 int resId; 365 if ("EC".equalsIgnoreCase(algorithm)) { 366 resId = R.raw.ec_key2_cert; 367 } else if ("RSA".equalsIgnoreCase(algorithm)) { 368 resId = R.raw.rsa_key1_cert; 369 } else { 370 throw new RuntimeException("Unsupported key algorithm: " + algorithm); 371 } 372 373 byte[] x509EncodedForm; 374 try (InputStream in = getContext().getResources().openRawResource(resId)) { 375 x509EncodedForm = TestUtils.drain(in); 376 } 377 X509EncodedKeySpec spec = new X509EncodedKeySpec(x509EncodedForm); 378 try { 379 KeyFactory keyFactory = getKeyFactory(algorithm); 380 try { 381 keyFactory.generatePublic(spec); 382 fail(); 383 } catch (InvalidKeySpecException expected) {} 384 } catch (Throwable e) { 385 throw new RuntimeException("Failed for " + algorithm, e); 386 } 387 } 388 } 389 390 public void testGeneratePrivateRejectsTransparentKeySpec() throws Exception { 391 for (String algorithm : EXPECTED_ALGORITHMS) { 392 int resId; 393 Class<? extends KeySpec> keySpecClass; 394 if ("EC".equalsIgnoreCase(algorithm)) { 395 resId = R.raw.ec_key2_pkcs8; 396 keySpecClass = ECPrivateKeySpec.class; 397 } else if ("RSA".equalsIgnoreCase(algorithm)) { 398 resId = R.raw.rsa_key2_pkcs8; 399 keySpecClass = RSAPrivateKeySpec.class; 400 } else { 401 throw new RuntimeException("Unsupported key algorithm: " + algorithm); 402 } 403 PrivateKey key = TestUtils.getRawResPrivateKey(getContext(), resId); 404 KeyFactory anotherKeyFactory = KeyFactory.getInstance(algorithm); 405 KeySpec spec = anotherKeyFactory.getKeySpec(key, keySpecClass); 406 407 try { 408 KeyFactory keyFactory = getKeyFactory(algorithm); 409 try { 410 keyFactory.generatePrivate(spec); 411 fail(); 412 } catch (InvalidKeySpecException expected) {} 413 } catch (Throwable e) { 414 throw new RuntimeException("Failed for " + algorithm, e); 415 } 416 } 417 } 418 419 public void testGeneratePublicRejectsTransparentKeySpec() throws Exception { 420 for (String algorithm : EXPECTED_ALGORITHMS) { 421 int resId; 422 Class<? extends KeySpec> keySpecClass; 423 if ("EC".equalsIgnoreCase(algorithm)) { 424 resId = R.raw.ec_key2_cert; 425 keySpecClass = ECPublicKeySpec.class; 426 } else if ("RSA".equalsIgnoreCase(algorithm)) { 427 resId = R.raw.rsa_key2_cert; 428 keySpecClass = RSAPublicKeySpec.class; 429 } else { 430 throw new RuntimeException("Unsupported key algorithm: " + algorithm); 431 } 432 PublicKey key = TestUtils.getRawResX509Certificate(getContext(), resId).getPublicKey(); 433 KeyFactory anotherKeyFactory = KeyFactory.getInstance(algorithm); 434 KeySpec spec = anotherKeyFactory.getKeySpec(key, keySpecClass); 435 436 try { 437 KeyFactory keyFactory = getKeyFactory(algorithm); 438 try { 439 keyFactory.generatePublic(spec); 440 fail(); 441 } catch (InvalidKeySpecException expected) {} 442 } catch (Throwable e) { 443 throw new RuntimeException("Failed for " + algorithm, e); 444 } 445 } 446 } 447 448 public void testGeneratePrivateAndPublicRejectKeyInfo() throws Exception { 449 for (String algorithm : EXPECTED_ALGORITHMS) { 450 try { 451 KeyPairGenerator keyGenerator = 452 KeyPairGenerator.getInstance(algorithm, EXPECTED_PROVIDER_NAME); 453 keyGenerator.initialize(new KeyGenParameterSpec.Builder("test1", 0).build()); 454 KeyPair keyPair = keyGenerator.generateKeyPair(); 455 KeyInfo keyInfo = TestUtils.getKeyInfo(keyPair.getPrivate()); 456 457 KeyFactory keyFactory = getKeyFactory(algorithm); 458 try { 459 keyFactory.generatePrivate(keyInfo); 460 fail(); 461 } catch (InvalidKeySpecException expected) {} 462 463 try { 464 keyFactory.generatePublic(keyInfo); 465 fail(); 466 } catch (InvalidKeySpecException expected) {} 467 } catch (Throwable e) { 468 throw new RuntimeException("Failed for " + algorithm, e); 469 } 470 } 471 } 472 473 private KeyFactory getKeyFactory(String algorithm) throws NoSuchAlgorithmException, 474 NoSuchProviderException { 475 return KeyFactory.getInstance(algorithm, EXPECTED_PROVIDER_NAME); 476 } 477 } 478