1 /* 2 * Copyright (C) 2014 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 package com.android.cts.deviceandprofileowner; 17 18 import static android.app.admin.DevicePolicyManager.ID_TYPE_BASE_INFO; 19 import static android.app.admin.DevicePolicyManager.ID_TYPE_IMEI; 20 import static android.app.admin.DevicePolicyManager.ID_TYPE_MEID; 21 import static android.app.admin.DevicePolicyManager.ID_TYPE_SERIAL; 22 import static android.keystore.cts.CertificateUtils.createCertificate; 23 24 import android.content.ComponentName; 25 import android.content.Context; 26 import android.content.res.AssetManager; 27 import android.keystore.cts.Attestation; 28 import android.keystore.cts.AuthorizationList; 29 import android.net.Uri; 30 import android.os.Build; 31 import android.security.AttestedKeyPair; 32 import android.security.KeyChain; 33 import android.security.KeyChainAliasCallback; 34 import android.security.KeyChainException; 35 import android.security.keystore.KeyGenParameterSpec; 36 import android.security.keystore.KeyProperties; 37 import android.support.test.uiautomator.UiDevice; 38 import android.telephony.TelephonyManager; 39 40 import com.android.compatibility.common.util.FakeKeys.FAKE_RSA_1; 41 42 import java.io.ByteArrayInputStream; 43 import java.io.ByteArrayOutputStream; 44 import java.io.IOException; 45 import java.io.InputStream; 46 import java.io.UnsupportedEncodingException; 47 import java.net.URLEncoder; 48 import java.security.GeneralSecurityException; 49 import java.security.KeyFactory; 50 import java.security.KeyPair; 51 import java.security.NoSuchAlgorithmException; 52 import java.security.PrivateKey; 53 import java.security.PublicKey; 54 import java.security.Signature; 55 import java.security.cert.Certificate; 56 import java.security.cert.CertificateException; 57 import java.security.cert.CertificateFactory; 58 import java.security.cert.CertificateParsingException; 59 import java.security.cert.X509Certificate; 60 import java.security.spec.InvalidKeySpecException; 61 import java.security.spec.PKCS8EncodedKeySpec; 62 import java.util.ArrayList; 63 import java.util.Arrays; 64 import java.util.Collection; 65 import java.util.List; 66 import java.util.concurrent.CountDownLatch; 67 import java.util.concurrent.TimeUnit; 68 69 import javax.security.auth.x500.X500Principal; 70 71 public class KeyManagementTest extends BaseDeviceAdminTest { 72 private static final long KEYCHAIN_TIMEOUT_MINS = 6; 73 74 private static class SupportedKeyAlgorithm { 75 public final String keyAlgorithm; 76 public final String signatureAlgorithm; 77 public final String[] signaturePaddingSchemes; 78 SupportedKeyAlgorithm( String keyAlgorithm, String signatureAlgorithm, String[] signaturePaddingSchemes)79 public SupportedKeyAlgorithm( 80 String keyAlgorithm, String signatureAlgorithm, 81 String[] signaturePaddingSchemes) { 82 this.keyAlgorithm = keyAlgorithm; 83 this.signatureAlgorithm = signatureAlgorithm; 84 this.signaturePaddingSchemes = signaturePaddingSchemes; 85 } 86 } 87 88 private final SupportedKeyAlgorithm[] SUPPORTED_KEY_ALGORITHMS = new SupportedKeyAlgorithm[] { 89 new SupportedKeyAlgorithm(KeyProperties.KEY_ALGORITHM_RSA, "SHA256withRSA", 90 new String[] {KeyProperties.SIGNATURE_PADDING_RSA_PSS, 91 KeyProperties.SIGNATURE_PADDING_RSA_PKCS1}), 92 new SupportedKeyAlgorithm(KeyProperties.KEY_ALGORITHM_EC, "SHA256withECDSA", null) 93 }; 94 95 private KeyManagementActivity mActivity; 96 97 @Override setUp()98 public void setUp() throws Exception { 99 super.setUp(); 100 final UiDevice device = UiDevice.getInstance(getInstrumentation()); 101 mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(), 102 KeyManagementActivity.class, null); 103 device.waitForIdle(); 104 } 105 106 @Override tearDown()107 public void tearDown() throws Exception { 108 mActivity.finish(); 109 super.tearDown(); 110 } 111 testCanInstallAndRemoveValidRsaKeypair()112 public void testCanInstallAndRemoveValidRsaKeypair() throws Exception { 113 final String alias = "com.android.test.valid-rsa-key-1"; 114 final PrivateKey privKey = getPrivateKey(FAKE_RSA_1.privateKey , "RSA"); 115 final Certificate cert = getCertificate(FAKE_RSA_1.caCertificate); 116 117 // Install keypair. 118 assertTrue(mDevicePolicyManager.installKeyPair(getWho(), privKey, cert, alias)); 119 try { 120 // Request and retrieve using the alias. 121 assertGranted(alias, false); 122 assertEquals(alias, new KeyChainAliasFuture(alias).get()); 123 assertGranted(alias, true); 124 125 // Verify key is at least something like the one we put in. 126 assertEquals(KeyChain.getPrivateKey(mActivity, alias).getAlgorithm(), "RSA"); 127 } finally { 128 // Delete regardless of whether the test succeeded. 129 assertTrue(mDevicePolicyManager.removeKeyPair(getWho(), alias)); 130 } 131 // Verify alias is actually deleted. 132 assertGranted(alias, false); 133 } 134 testCanInstallWithAutomaticAccess()135 public void testCanInstallWithAutomaticAccess() throws Exception { 136 final String grant = "com.android.test.autogrant-key-1"; 137 final String withhold = "com.android.test.nongrant-key-1"; 138 final PrivateKey privKey = getPrivateKey(FAKE_RSA_1.privateKey , "RSA"); 139 final Certificate cert = getCertificate(FAKE_RSA_1.caCertificate); 140 141 // Install keypairs. 142 assertTrue(mDevicePolicyManager.installKeyPair(getWho(), privKey, new Certificate[] {cert}, 143 grant, true)); 144 assertTrue(mDevicePolicyManager.installKeyPair(getWho(), privKey, new Certificate[] {cert}, 145 withhold, false)); 146 try { 147 // Verify only the requested key was actually granted. 148 assertGranted(grant, true); 149 assertGranted(withhold, false); 150 151 // Verify the granted key is actually obtainable in PrivateKey form. 152 assertEquals(KeyChain.getPrivateKey(mActivity, grant).getAlgorithm(), "RSA"); 153 } finally { 154 // Delete both keypairs. 155 assertTrue(mDevicePolicyManager.removeKeyPair(getWho(), grant)); 156 assertTrue(mDevicePolicyManager.removeKeyPair(getWho(), withhold)); 157 } 158 // Verify they're actually gone. 159 assertGranted(grant, false); 160 assertGranted(withhold, false); 161 } 162 loadCertificateChain(String assetName)163 private List<Certificate> loadCertificateChain(String assetName) throws Exception { 164 final Collection<Certificate> certs = loadCertificatesFromAsset(assetName); 165 final ArrayList<Certificate> certChain = new ArrayList(certs); 166 // Some sanity check on the cert chain 167 assertTrue(certs.size() > 1); 168 for (int i = 1; i < certChain.size(); i++) { 169 certChain.get(i - 1).verify(certChain.get(i).getPublicKey()); 170 } 171 return certChain; 172 } 173 testCanInstallCertChain()174 public void testCanInstallCertChain() throws Exception { 175 // Use assets/generate-client-cert-chain.sh to regenerate the client cert chain. 176 final PrivateKey privKey = loadPrivateKeyFromAsset("user-cert-chain.key"); 177 final Certificate[] certChain = loadCertificateChain("user-cert-chain.crt") 178 .toArray(new Certificate[0]); 179 final String alias = "com.android.test.clientkeychain"; 180 181 // Install keypairs. 182 assertTrue(mDevicePolicyManager.installKeyPair(getWho(), privKey, certChain, alias, true)); 183 try { 184 // Verify only the requested key was actually granted. 185 assertGranted(alias, true); 186 187 // Verify the granted key is actually obtainable in PrivateKey form. 188 assertEquals(KeyChain.getPrivateKey(mActivity, alias).getAlgorithm(), "RSA"); 189 190 // Verify the certificate chain is correct 191 X509Certificate[] returnedCerts = KeyChain.getCertificateChain(mActivity, alias); 192 assertTrue(Arrays.equals(certChain, returnedCerts)); 193 } finally { 194 // Delete both keypairs. 195 assertTrue(mDevicePolicyManager.removeKeyPair(getWho(), alias)); 196 } 197 // Verify they're actually gone. 198 assertGranted(alias, false); 199 } 200 testGrantsDoNotPersistBetweenInstallations()201 public void testGrantsDoNotPersistBetweenInstallations() throws Exception { 202 final String alias = "com.android.test.persistent-key-1"; 203 final PrivateKey privKey = getPrivateKey(FAKE_RSA_1.privateKey , "RSA"); 204 final Certificate cert = getCertificate(FAKE_RSA_1.caCertificate); 205 206 // Install keypair. 207 assertTrue(mDevicePolicyManager.installKeyPair(getWho(), privKey, new Certificate[] {cert}, 208 alias, true)); 209 try { 210 assertGranted(alias, true); 211 } finally { 212 // Delete and verify. 213 assertTrue(mDevicePolicyManager.removeKeyPair(getWho(), alias)); 214 } 215 assertGranted(alias, false); 216 217 // Install again. 218 assertTrue(mDevicePolicyManager.installKeyPair(getWho(), privKey, new Certificate[] {cert}, 219 alias, false)); 220 try { 221 assertGranted(alias, false); 222 } finally { 223 // Delete. 224 assertTrue(mDevicePolicyManager.removeKeyPair(getWho(), alias)); 225 } 226 } 227 testNullKeyParamsFailPredictably()228 public void testNullKeyParamsFailPredictably() throws Exception { 229 final String alias = "com.android.test.null-key-1"; 230 final PrivateKey privKey = getPrivateKey(FAKE_RSA_1.privateKey, "RSA"); 231 final Certificate cert = getCertificate(FAKE_RSA_1.caCertificate); 232 try { 233 mDevicePolicyManager.installKeyPair(getWho(), null, cert, alias); 234 fail("Exception should have been thrown for null PrivateKey"); 235 } catch (NullPointerException expected) { 236 } 237 try { 238 mDevicePolicyManager.installKeyPair(getWho(), privKey, null, alias); 239 fail("Exception should have been thrown for null Certificate"); 240 } catch (NullPointerException expected) { 241 } 242 } 243 testNullAdminComponentIsDenied()244 public void testNullAdminComponentIsDenied() throws Exception { 245 final String alias = "com.android.test.null-admin-1"; 246 final PrivateKey privKey = getPrivateKey(FAKE_RSA_1.privateKey, "RSA"); 247 final Certificate cert = getCertificate(FAKE_RSA_1.caCertificate); 248 try { 249 mDevicePolicyManager.installKeyPair(null, privKey, cert, alias); 250 fail("Exception should have been thrown for null ComponentName"); 251 } catch (SecurityException expected) { 252 } 253 } 254 testNotUserSelectableAliasCanBeChosenViaPolicy()255 public void testNotUserSelectableAliasCanBeChosenViaPolicy() throws Exception { 256 final String alias = "com.android.test.not-selectable-key-1"; 257 final PrivateKey privKey = getPrivateKey(FAKE_RSA_1.privateKey , "RSA"); 258 final Certificate cert = getCertificate(FAKE_RSA_1.caCertificate); 259 260 // Install keypair. 261 assertTrue(mDevicePolicyManager.installKeyPair( 262 getWho(), privKey, new Certificate[] {cert}, alias, 0)); 263 try { 264 // Request and retrieve using the alias. 265 assertGranted(alias, false); 266 assertEquals(alias, new KeyChainAliasFuture(alias).get()); 267 assertGranted(alias, true); 268 } finally { 269 // Delete regardless of whether the test succeeded. 270 assertTrue(mDevicePolicyManager.removeKeyPair(getWho(), alias)); 271 } 272 } 273 signDataWithKey(String algoIdentifier, PrivateKey privateKey)274 byte[] signDataWithKey(String algoIdentifier, PrivateKey privateKey) throws Exception { 275 byte[] data = new String("hello").getBytes(); 276 Signature sign = Signature.getInstance(algoIdentifier); 277 sign.initSign(privateKey); 278 sign.update(data); 279 return sign.sign(); 280 } 281 verifySignature(String algoIdentifier, PublicKey publicKey, byte[] signature)282 void verifySignature(String algoIdentifier, PublicKey publicKey, byte[] signature) 283 throws Exception { 284 byte[] data = new String("hello").getBytes(); 285 Signature verify = Signature.getInstance(algoIdentifier); 286 verify.initVerify(publicKey); 287 verify.update(data); 288 assertTrue(verify.verify(signature)); 289 } 290 verifySignatureOverData(String algoIdentifier, KeyPair keyPair)291 void verifySignatureOverData(String algoIdentifier, KeyPair keyPair) throws Exception { 292 verifySignature(algoIdentifier, keyPair.getPublic(), 293 signDataWithKey(algoIdentifier, keyPair.getPrivate())); 294 } 295 testCanGenerateRSAKeyPair()296 public void testCanGenerateRSAKeyPair() throws Exception { 297 final String alias = "com.android.test.generated-rsa-1"; 298 try { 299 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder( 300 alias, 301 KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY) 302 .setKeySize(2048) 303 .setDigests(KeyProperties.DIGEST_SHA256) 304 .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PSS, 305 KeyProperties.SIGNATURE_PADDING_RSA_PKCS1) 306 .build(); 307 308 AttestedKeyPair generated = mDevicePolicyManager.generateKeyPair( 309 getWho(), "RSA", spec, 0); 310 assertNotNull(generated); 311 verifySignatureOverData("SHA256withRSA", generated.getKeyPair()); 312 } finally { 313 assertTrue(mDevicePolicyManager.removeKeyPair(getWho(), alias)); 314 } 315 } 316 testCanGenerateECKeyPair()317 public void testCanGenerateECKeyPair() throws Exception { 318 final String alias = "com.android.test.generated-ec-1"; 319 try { 320 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder( 321 alias, 322 KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY) 323 .setDigests(KeyProperties.DIGEST_SHA256) 324 .build(); 325 326 AttestedKeyPair generated = mDevicePolicyManager.generateKeyPair( 327 getWho(), "EC", spec, 0); 328 assertNotNull(generated); 329 verifySignatureOverData("SHA256withECDSA", generated.getKeyPair()); 330 } finally { 331 assertTrue(mDevicePolicyManager.removeKeyPair(getWho(), alias)); 332 } 333 } 334 validateDeviceIdAttestationData(Certificate leaf, String expectedSerial, String expectedImei, String expectedMeid)335 private void validateDeviceIdAttestationData(Certificate leaf, 336 String expectedSerial, String expectedImei, String expectedMeid) 337 throws CertificateParsingException { 338 Attestation attestationRecord = new Attestation((X509Certificate) leaf); 339 AuthorizationList teeAttestation = attestationRecord.getTeeEnforced(); 340 assertNotNull(teeAttestation); 341 assertEquals(Build.BRAND, teeAttestation.getBrand()); 342 assertEquals(Build.DEVICE, teeAttestation.getDevice()); 343 assertEquals(Build.PRODUCT, teeAttestation.getProduct()); 344 assertEquals(Build.MANUFACTURER, teeAttestation.getManufacturer()); 345 assertEquals(Build.MODEL, teeAttestation.getModel()); 346 assertEquals(expectedSerial, teeAttestation.getSerialNumber()); 347 assertEquals(expectedImei, teeAttestation.getImei()); 348 assertEquals(expectedMeid, teeAttestation.getMeid()); 349 } 350 validateAttestationRecord(List<Certificate> attestation, byte[] providedChallenge)351 private void validateAttestationRecord(List<Certificate> attestation, 352 byte[] providedChallenge) throws CertificateParsingException { 353 assertNotNull(attestation); 354 assertTrue(attestation.size() >= 2); 355 X509Certificate leaf = (X509Certificate) attestation.get(0); 356 Attestation attestationRecord = new Attestation(leaf); 357 assertTrue(Arrays.equals(providedChallenge, 358 attestationRecord.getAttestationChallenge())); 359 } 360 validateSignatureChain(List<Certificate> chain, PublicKey leafKey)361 private void validateSignatureChain(List<Certificate> chain, PublicKey leafKey) 362 throws GeneralSecurityException { 363 X509Certificate leaf = (X509Certificate) chain.get(0); 364 PublicKey keyFromCert = leaf.getPublicKey(); 365 assertTrue(Arrays.equals(keyFromCert.getEncoded(), leafKey.getEncoded())); 366 // Check that the certificate chain is valid. 367 for (int i = 1; i < chain.size(); i++) { 368 X509Certificate intermediate = (X509Certificate) chain.get(i); 369 PublicKey intermediateKey = intermediate.getPublicKey(); 370 leaf.verify(intermediateKey); 371 leaf = intermediate; 372 } 373 374 // leaf is now the root, verify the root is self-signed. 375 PublicKey rootKey = leaf.getPublicKey(); 376 leaf.verify(rootKey); 377 } 378 isDeviceIdAttestationSupported()379 private boolean isDeviceIdAttestationSupported() { 380 return mDevicePolicyManager.isDeviceIdAttestationSupported(); 381 } 382 isDeviceIdAttestationRequested(int deviceIdAttestationFlags)383 private boolean isDeviceIdAttestationRequested(int deviceIdAttestationFlags) { 384 return deviceIdAttestationFlags != 0; 385 } 386 387 /** 388 * Generates a key using DevicePolicyManager.generateKeyPair using the given key algorithm, 389 * then test signing and verifying using generated key. 390 * If {@code signaturePaddings} is not null, it is added to the key parameters specification. 391 * Returns the Attestation leaf certificate. 392 */ generateKeyAndCheckAttestation( String keyAlgorithm, String signatureAlgorithm, String[] signaturePaddings, int deviceIdAttestationFlags)393 private Certificate generateKeyAndCheckAttestation( 394 String keyAlgorithm, String signatureAlgorithm, 395 String[] signaturePaddings, int deviceIdAttestationFlags) 396 throws Exception { 397 final String alias = 398 String.format("com.android.test.attested-%s", keyAlgorithm.toLowerCase()); 399 byte[] attestationChallenge = new byte[] {0x01, 0x02, 0x03}; 400 try { 401 KeyGenParameterSpec.Builder specBuilder = new KeyGenParameterSpec.Builder( 402 alias, 403 KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY) 404 .setDigests(KeyProperties.DIGEST_SHA256) 405 .setAttestationChallenge(attestationChallenge); 406 if (signaturePaddings != null) { 407 specBuilder.setSignaturePaddings(signaturePaddings); 408 } 409 410 KeyGenParameterSpec spec = specBuilder.build(); 411 AttestedKeyPair generated = mDevicePolicyManager.generateKeyPair( 412 getWho(), keyAlgorithm, spec, deviceIdAttestationFlags); 413 // If Device ID attestation was requested, check it succeeded if and only if device ID 414 // attestation is supported. 415 if (isDeviceIdAttestationRequested(deviceIdAttestationFlags)) { 416 if (generated == null) { 417 assertFalse(String.format("Failed getting Device ID attestation for key " + 418 "algorithm %s, with flags %s, despite device declaring support.", 419 keyAlgorithm, deviceIdAttestationFlags), 420 isDeviceIdAttestationSupported()); 421 return null; 422 } else { 423 assertTrue(String.format("Device ID attestation for key " + 424 "algorithm %s, with flags %d should not have succeeded.", 425 keyAlgorithm, deviceIdAttestationFlags), 426 isDeviceIdAttestationSupported()); 427 } 428 } else { 429 assertNotNull( 430 String.format("Key generation (of type %s) must succeed when Device ID " + 431 "attestation was not requested.", keyAlgorithm), generated); 432 } 433 final KeyPair keyPair = generated.getKeyPair(); 434 verifySignatureOverData(signatureAlgorithm, keyPair); 435 List<Certificate> attestation = generated.getAttestationRecord(); 436 validateAttestationRecord(attestation, attestationChallenge); 437 validateSignatureChain(attestation, keyPair.getPublic()); 438 return attestation.get(0); 439 } catch (UnsupportedOperationException ex) { 440 assertTrue(String.format("Unexpected failure while generating key %s with ID flags %d: %s", 441 keyAlgorithm, deviceIdAttestationFlags, ex), 442 isDeviceIdAttestationRequested(deviceIdAttestationFlags) && 443 !isDeviceIdAttestationSupported()); 444 return null; 445 } finally { 446 assertTrue(mDevicePolicyManager.removeKeyPair(getWho(), alias)); 447 } 448 } 449 450 /** 451 * Test key generation, including requesting Key Attestation, for all supported key 452 * algorithms. 453 */ testCanGenerateKeyPairWithKeyAttestation()454 public void testCanGenerateKeyPairWithKeyAttestation() throws Exception { 455 for (SupportedKeyAlgorithm supportedKey: SUPPORTED_KEY_ALGORITHMS) { 456 assertNotNull(generateKeyAndCheckAttestation( 457 supportedKey.keyAlgorithm, supportedKey.signatureAlgorithm, 458 supportedKey.signaturePaddingSchemes, 0)); 459 } 460 } 461 testAllVariationsOfDeviceIdAttestation()462 public void testAllVariationsOfDeviceIdAttestation() throws Exception { 463 List<Integer> modesToTest = new ArrayList<Integer>(); 464 String imei = null; 465 String meid = null; 466 // All devices must support at least basic device information attestation as well as serial 467 // number attestation. Although attestation of unique device ids are only callable by device 468 // owner. 469 modesToTest.add(ID_TYPE_BASE_INFO); 470 if (isDeviceOwner()) { 471 modesToTest.add(ID_TYPE_SERIAL); 472 // Get IMEI and MEID of the device. 473 TelephonyManager telephonyService = (TelephonyManager) mActivity.getSystemService( 474 Context.TELEPHONY_SERVICE); 475 assertNotNull("Need to be able to read device identifiers", telephonyService); 476 imei = telephonyService.getImei(0); 477 meid = telephonyService.getMeid(0); 478 // If the device has a valid IMEI it must support attestation for it. 479 if (imei != null) { 480 modesToTest.add(ID_TYPE_IMEI); 481 } 482 // Same for MEID 483 if (meid != null) { 484 modesToTest.add(ID_TYPE_MEID); 485 } 486 } 487 int numCombinations = 1 << modesToTest.size(); 488 for (int i = 1; i < numCombinations; i++) { 489 // Set the bits in devIdOpt to be passed into generateKeyPair according to the 490 // current modes tested. 491 int devIdOpt = 0; 492 for (int j = 0; j < modesToTest.size(); j++) { 493 if ((i & (1 << j)) != 0) { 494 devIdOpt = devIdOpt | modesToTest.get(j); 495 } 496 } 497 try { 498 // Now run the test with all supported key algorithms 499 for (SupportedKeyAlgorithm supportedKey: SUPPORTED_KEY_ALGORITHMS) { 500 Certificate attestation = generateKeyAndCheckAttestation( 501 supportedKey.keyAlgorithm, supportedKey.signatureAlgorithm, 502 supportedKey.signaturePaddingSchemes, devIdOpt); 503 // generateKeyAndCheckAttestation should return null if device ID attestation 504 // is not supported. Simply continue to test the next combination. 505 if (attestation == null && !isDeviceIdAttestationSupported()) { 506 continue; 507 } 508 assertNotNull(String.format( 509 "Attestation should be valid for key %s with attestation modes %s", 510 supportedKey.keyAlgorithm, devIdOpt), attestation); 511 // Set the expected values for serial, IMEI and MEID depending on whether 512 // attestation for them was requested. 513 String expectedSerial = null; 514 if ((devIdOpt & ID_TYPE_SERIAL) != 0) { 515 expectedSerial = Build.getSerial(); 516 } 517 String expectedImei = null; 518 if ((devIdOpt & ID_TYPE_IMEI) != 0) { 519 expectedImei = imei; 520 } 521 String expectedMeid = null; 522 if ((devIdOpt & ID_TYPE_MEID) != 0) { 523 expectedMeid = meid; 524 } 525 validateDeviceIdAttestationData(attestation, expectedSerial, expectedImei, 526 expectedMeid); 527 } 528 } catch (UnsupportedOperationException expected) { 529 // Make sure the test only fails if the device is not meant to support Device 530 // ID attestation. 531 assertFalse(isDeviceIdAttestationSupported()); 532 } 533 } 534 } 535 testProfileOwnerCannotAttestDeviceUniqueIds()536 public void testProfileOwnerCannotAttestDeviceUniqueIds() throws Exception { 537 if (isDeviceOwner()) { 538 return; 539 } 540 int[] forbiddenModes = new int[] {ID_TYPE_SERIAL, ID_TYPE_IMEI, ID_TYPE_MEID}; 541 for (int i = 0; i < forbiddenModes.length; i++) { 542 try { 543 for (SupportedKeyAlgorithm supportedKey: SUPPORTED_KEY_ALGORITHMS) { 544 generateKeyAndCheckAttestation(supportedKey.keyAlgorithm, 545 supportedKey.signatureAlgorithm, 546 supportedKey.signaturePaddingSchemes, 547 forbiddenModes[i]); 548 fail("Attestation of device UID (" + forbiddenModes[i] + ") should not be " 549 + "possible from profile owner"); 550 } 551 } catch (SecurityException e) { 552 assertTrue(e.getMessage().contains("does not own the device")); 553 } 554 } 555 } 556 testCanSetKeyPairCert()557 public void testCanSetKeyPairCert() throws Exception { 558 final String alias = "com.android.test.set-ec-1"; 559 try { 560 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder( 561 alias, 562 KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY) 563 .setDigests(KeyProperties.DIGEST_SHA256) 564 .build(); 565 566 AttestedKeyPair generated = mDevicePolicyManager.generateKeyPair( 567 getWho(), "EC", spec, 0); 568 assertNotNull(generated); 569 // Create a self-signed cert to go with it. 570 X500Principal issuer = new X500Principal("CN=SelfSigned, O=Android, C=US"); 571 X500Principal subject = new X500Principal("CN=Subject, O=Android, C=US"); 572 X509Certificate cert = createCertificate(generated.getKeyPair(), subject, issuer); 573 // Set the certificate chain 574 List<Certificate> certs = new ArrayList<Certificate>(); 575 certs.add(cert); 576 mDevicePolicyManager.setKeyPairCertificate(getWho(), alias, certs, true); 577 // Make sure that the alias can now be obtained. 578 assertEquals(alias, new KeyChainAliasFuture(alias).get()); 579 // And can be retrieved from KeyChain 580 X509Certificate[] fetchedCerts = KeyChain.getCertificateChain(mActivity, alias); 581 assertEquals(fetchedCerts.length, certs.size()); 582 assertTrue(Arrays.equals(fetchedCerts[0].getEncoded(), certs.get(0).getEncoded())); 583 } finally { 584 assertTrue(mDevicePolicyManager.removeKeyPair(getWho(), alias)); 585 } 586 } 587 testCanSetKeyPairCertChain()588 public void testCanSetKeyPairCertChain() throws Exception { 589 final String alias = "com.android.test.set-ec-2"; 590 try { 591 KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder( 592 alias, 593 KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY) 594 .setDigests(KeyProperties.DIGEST_SHA256) 595 .build(); 596 597 AttestedKeyPair generated = mDevicePolicyManager.generateKeyPair( 598 getWho(), "EC", spec, 0); 599 assertNotNull(generated); 600 List<Certificate> chain = loadCertificateChain("user-cert-chain.crt"); 601 mDevicePolicyManager.setKeyPairCertificate(getWho(), alias, chain, true); 602 // Make sure that the alias can now be obtained. 603 assertEquals(alias, new KeyChainAliasFuture(alias).get()); 604 // And can be retrieved from KeyChain 605 X509Certificate[] fetchedCerts = KeyChain.getCertificateChain(mActivity, alias); 606 assertEquals(fetchedCerts.length, chain.size()); 607 for (int i = 0; i < chain.size(); i++) { 608 assertTrue(Arrays.equals(fetchedCerts[i].getEncoded(), chain.get(i).getEncoded())); 609 } 610 } finally { 611 assertTrue(mDevicePolicyManager.removeKeyPair(getWho(), alias)); 612 } 613 } 614 assertGranted(String alias, boolean expected)615 private void assertGranted(String alias, boolean expected) throws InterruptedException { 616 boolean granted = false; 617 try { 618 granted = (KeyChain.getPrivateKey(mActivity, alias) != null); 619 } catch (KeyChainException e) { 620 if (expected) { 621 e.printStackTrace(); 622 } 623 } 624 assertEquals("Grant for alias: \"" + alias + "\"", expected, granted); 625 } 626 getPrivateKey(final byte[] key, String type)627 private static PrivateKey getPrivateKey(final byte[] key, String type) 628 throws NoSuchAlgorithmException, InvalidKeySpecException { 629 return KeyFactory.getInstance(type).generatePrivate( 630 new PKCS8EncodedKeySpec(key)); 631 } 632 getCertificate(byte[] cert)633 private static Certificate getCertificate(byte[] cert) throws CertificateException { 634 return CertificateFactory.getInstance("X.509").generateCertificate( 635 new ByteArrayInputStream(cert)); 636 } 637 loadCertificatesFromAsset(String assetName)638 private Collection<Certificate> loadCertificatesFromAsset(String assetName) { 639 try { 640 final CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); 641 AssetManager am = mActivity.getAssets(); 642 InputStream is = am.open(assetName); 643 return (Collection<Certificate>) certFactory.generateCertificates(is); 644 } catch (IOException | CertificateException e) { 645 e.printStackTrace(); 646 } 647 return null; 648 } 649 loadPrivateKeyFromAsset(String assetName)650 private PrivateKey loadPrivateKeyFromAsset(String assetName) { 651 try { 652 AssetManager am = mActivity.getAssets(); 653 InputStream is = am.open(assetName); 654 ByteArrayOutputStream output = new ByteArrayOutputStream(); 655 int length; 656 byte[] buffer = new byte[4096]; 657 while ((length = is.read(buffer, 0, buffer.length)) != -1) { 658 output.write(buffer, 0, length); 659 } 660 return getPrivateKey(output.toByteArray(), "RSA"); 661 } catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException e) { 662 e.printStackTrace(); 663 } 664 return null; 665 } 666 667 private class KeyChainAliasFuture implements KeyChainAliasCallback { 668 private final CountDownLatch mLatch = new CountDownLatch(1); 669 private String mChosenAlias = null; 670 671 @Override alias(final String chosenAlias)672 public void alias(final String chosenAlias) { 673 mChosenAlias = chosenAlias; 674 mLatch.countDown(); 675 } 676 KeyChainAliasFuture(String alias)677 public KeyChainAliasFuture(String alias) 678 throws UnsupportedEncodingException { 679 /* Pass the alias as a GET to an imaginary server instead of explicitly asking for it, 680 * to make sure the DPC actually has to do some work to grant the cert. 681 */ 682 final Uri uri = 683 Uri.parse("https://example.org/?alias=" + URLEncoder.encode(alias, "UTF-8")); 684 KeyChain.choosePrivateKeyAlias(mActivity, this, 685 null /* keyTypes */, null /* issuers */, uri, null /* alias */); 686 } 687 get()688 public String get() throws InterruptedException { 689 assertTrue("Chooser timeout", mLatch.await(KEYCHAIN_TIMEOUT_MINS, TimeUnit.MINUTES)); 690 return mChosenAlias; 691 } 692 } 693 getWho()694 protected ComponentName getWho() { 695 return ADMIN_RECEIVER_COMPONENT; 696 } 697 } 698