am 27da12ff: Merge "[devicepolicy] More complete test of CaCert API" into marshmallow-cts-dev am: 66963f6780
* commit '27da12ffb387cc8b61c8531764240f77fdae224b':
[devicepolicy] More complete test of CaCert API
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CaCertManagementTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CaCertManagementTest.java
index 9127dab..51c575c 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CaCertManagementTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CaCertManagementTest.java
@@ -15,69 +15,143 @@
*/
package com.android.cts.deviceowner;
-import static com.android.cts.deviceowner.FakeKeys.FAKE_RSA_1;
-import static com.android.cts.deviceowner.FakeKeys.FAKE_DSA_1;
-
import java.io.ByteArrayInputStream;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
-import java.security.cert.Certificate;
+import java.util.Arrays;
import java.util.List;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+
+import static com.android.cts.deviceowner.FakeKeys.FAKE_DSA_1;
+import static com.android.cts.deviceowner.FakeKeys.FAKE_RSA_1;
+
public class CaCertManagementTest extends BaseDeviceOwnerTest {
+ /**
+ * Test: device admins should be able to list all installed certs.
+ *
+ * <p>The list of certificates must never be {@code null}.
+ */
public void testCanRetrieveListOfInstalledCaCerts() {
List<byte[]> caCerts = mDevicePolicyManager.getInstalledCaCerts(getWho());
assertNotNull(caCerts);
}
+ /**
+ * Test: a valid cert should be installable and also removable.
+ */
public void testCanInstallAndUninstallACaCert()
- throws CertificateException {
- assertFalse(hasCaCertInstalled(FAKE_RSA_1.caCertificate));
- assertFalse(hasCaCertInstalled(FAKE_DSA_1.caCertificate));
+ throws CertificateException, GeneralSecurityException {
+ assertUninstalled(FAKE_RSA_1.caCertificate);
+ assertUninstalled(FAKE_DSA_1.caCertificate);
+
assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_RSA_1.caCertificate));
- assertTrue(hasCaCertInstalled(FAKE_RSA_1.caCertificate));
- assertFalse(hasCaCertInstalled(FAKE_DSA_1.caCertificate));
+ assertInstalled(FAKE_RSA_1.caCertificate);
+ assertUninstalled(FAKE_DSA_1.caCertificate);
+
mDevicePolicyManager.uninstallCaCert(getWho(), FAKE_RSA_1.caCertificate);
- assertFalse(hasCaCertInstalled(FAKE_RSA_1.caCertificate));
- assertFalse(hasCaCertInstalled(FAKE_DSA_1.caCertificate));
+ assertUninstalled(FAKE_RSA_1.caCertificate);
+ assertUninstalled(FAKE_DSA_1.caCertificate);
}
- public void testUninstallationIsSelective() throws CertificateException {
+ /**
+ * Test: removing one certificate must not remove any others.
+ */
+ public void testUninstallationIsSelective()
+ throws CertificateException, GeneralSecurityException {
assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_RSA_1.caCertificate));
assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_DSA_1.caCertificate));
+
mDevicePolicyManager.uninstallCaCert(getWho(), FAKE_DSA_1.caCertificate);
- assertTrue(hasCaCertInstalled(FAKE_RSA_1.caCertificate));
- assertFalse(hasCaCertInstalled(FAKE_DSA_1.caCertificate));
+ assertInstalled(FAKE_RSA_1.caCertificate);
+ assertUninstalled(FAKE_DSA_1.caCertificate);
+
mDevicePolicyManager.uninstallCaCert(getWho(), FAKE_RSA_1.caCertificate);
}
- public void testCanUninstallAllUserCaCerts() throws CertificateException {
+ /**
+ * Test: uninstallAllUserCaCerts should be equivalent to calling uninstallCaCert on every
+ * supplementary installed certificate.
+ */
+ public void testCanUninstallAllUserCaCerts()
+ throws CertificateException, GeneralSecurityException {
assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_RSA_1.caCertificate));
assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_DSA_1.caCertificate));
+
mDevicePolicyManager.uninstallAllUserCaCerts(getWho());
- assertFalse(hasCaCertInstalled(FAKE_RSA_1.caCertificate));
- assertFalse(hasCaCertInstalled(FAKE_DSA_1.caCertificate));
+ assertUninstalled(FAKE_RSA_1.caCertificate);
+ assertUninstalled(FAKE_DSA_1.caCertificate);
}
- private boolean hasCaCertInstalled(byte [] caCert) throws CertificateException {
- boolean result = mDevicePolicyManager.hasCaCertInstalled(getWho(), caCert);
- assertEquals(result, containsCertificate(
- mDevicePolicyManager.getInstalledCaCerts(getWho()), caCert));
- return result;
+ private void assertInstalled(byte[] caBytes)
+ throws CertificateException, GeneralSecurityException {
+ Certificate caCert = readCertificate(caBytes);
+ assertTrue(isCaCertInstalledAndTrusted(caCert));
}
- private static boolean containsCertificate(List<byte[]> certificates, byte [] toMatch)
- throws CertificateException {
- Certificate certificateToMatch = readCertificate(toMatch);
- for (byte[] certBuffer : certificates) {
- Certificate cert = readCertificate(certBuffer);
- if (certificateToMatch.equals(cert)) {
- return true;
+ private void assertUninstalled(byte[] caBytes)
+ throws CertificateException, GeneralSecurityException {
+ Certificate caCert = readCertificate(caBytes);
+ assertFalse(isCaCertInstalledAndTrusted(caCert));
+ }
+
+ /**
+ * Whether a given cert, or one a lot like it, has been installed system-wide and is available
+ * to all apps.
+ *
+ * <p>A CA certificate is "installed" if it matches all of the following conditions:
+ * <ul>
+ * <li>{@link DevicePolicyManager#hasCaCertInstalled} returns {@code true}.</li>
+ * <li>{@link DevicePolicyManager#getInstalledCaCerts} lists a matching certificate (not
+ * necessarily exactly the same) in its response.</li>
+ * <li>Any new instances of {@link TrustManager} should report the certificate among their
+ * accepted issuer list -- older instances may keep the set of issuers they were created
+ * with until explicitly refreshed.</li>
+ *
+ * @return {@code true} if installed by all metrics, {@code false} if not installed by any
+ * metric. In any other case an {@link AssertionError} will be thrown.
+ */
+ private boolean isCaCertInstalledAndTrusted(Certificate caCert)
+ throws GeneralSecurityException, CertificateException {
+ boolean installed = mDevicePolicyManager.hasCaCertInstalled(getWho(), caCert.getEncoded());
+
+ boolean listed = false;
+ for (byte[] certBuffer : mDevicePolicyManager.getInstalledCaCerts(getWho())) {
+ if (caCert.equals(readCertificate(certBuffer))) {
+ listed = true;
}
}
- return false;
+
+ boolean trusted = false;
+ final TrustManagerFactory tmf =
+ TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init((KeyStore) null);
+ for (TrustManager trustManager : tmf.getTrustManagers()) {
+ if (trustManager instanceof X509TrustManager) {
+ final X509TrustManager tm = (X509TrustManager) trustManager;
+ if (Arrays.asList(tm.getAcceptedIssuers()).contains(caCert)) {
+ trusted = true;
+ }
+ }
+ }
+
+ // All three responses should match - if an installed certificate isn't trusted or (worse)
+ // a trusted certificate isn't even installed we should
+ assertEquals(installed, listed);
+ assertEquals(installed, trusted);
+ return installed;
}
+ /**
+ * Convert an encoded certificate back into a {@link Certificate}.
+ *
+ * Instantiates a fresh CertificateFactory every time for repeatability.
+ */
private static Certificate readCertificate(byte[] certBuffer) throws CertificateException {
final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
return certFactory.generateCertificate(new ByteArrayInputStream(certBuffer));