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